Add Mastodon comments and remove date-fns dependency

This commit is contained in:
Bad Manners 2024-03-27 11:54:18 -03:00
parent 00fa1fb164
commit 3e8bcbcf43
19 changed files with 393 additions and 142 deletions

View file

@ -1,7 +1,6 @@
import rss, { type RSSFeedItem } from "@astrojs/rss";
import type { APIRoute } from "astro";
import { getCollection } from "astro:content";
import { getUnixTime, addMinutes } from "date-fns";
type FeedItem = RSSFeedItem & {
pubDate: Date;
@ -9,9 +8,19 @@ type FeedItem = RSSFeedItem & {
const MAX_ITEMS = 10;
function toNoonUTCDate(date: Date) {
const adjustedDate = new Date(date);
adjustedDate.setUTCHours(12);
return adjustedDate;
}
export const GET: APIRoute = async ({ site }) => {
const stories = (await getCollection("stories", (story) => !story.data.isDraft)).sort((a, b) => getUnixTime(b.data.pubDate) - getUnixTime(a.data.pubDate)).slice(0, MAX_ITEMS);
const games = (await getCollection("games", (game) => !game.data.isDraft)).sort((a, b) => getUnixTime(b.data.pubDate) - getUnixTime(a.data.pubDate)).slice(0, MAX_ITEMS);
const stories = (await getCollection("stories", (story) => !story.data.isDraft))
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
.slice(0, MAX_ITEMS);
const games = (await getCollection("games", (game) => !game.data.isDraft))
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
.slice(0, MAX_ITEMS);
return rss({
title: "Gallery | Bad Manners",
description: "Stories, games, and (possibly) more by Bad Manners",
@ -19,7 +28,7 @@ export const GET: APIRoute = async ({ site }) => {
items: [
stories.map<FeedItem>((story) => ({
title: `New story! "${story.data.title}"`,
pubDate: addMinutes(story.data.pubDate, 12 * 60 - story.data.pubDate.getTimezoneOffset()),
pubDate: toNoonUTCDate(story.data.pubDate),
link: `/stories/${story.slug}`,
description:
`Word count: ${story.data.wordCount}. ${story.data.contentWarning} ${story.data.descriptionPlaintext || story.data.description}`
@ -29,7 +38,7 @@ export const GET: APIRoute = async ({ site }) => {
})),
games.map<FeedItem>((game) => ({
title: `New game! "${game.data.title}"`,
pubDate: addMinutes(game.data.pubDate, 12 * 60 - game.data.pubDate.getTimezoneOffset()),
pubDate: toNoonUTCDate(game.data.pubDate),
link: `/games/${game.slug}`,
description: `${game.data.contentWarning} ${game.data.descriptionPlaintext || game.data.description}`
.replaceAll(/[\n ]+/g, " ")
@ -38,7 +47,7 @@ export const GET: APIRoute = async ({ site }) => {
})),
]
.flat()
.sort((a, b) => getUnixTime(b.pubDate) - getUnixTime(a.pubDate))
.sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime())
.slice(0, MAX_ITEMS),
});
};

View file

@ -1,12 +1,10 @@
---
import { Image } from "astro:assets";
import { getCollection } from "astro:content";
import { getUnixTime, format as formatDate } from "date-fns";
import { enUS as enUSLocale } from "date-fns/locale/en-US";
import GalleryLayout from "../layouts/GalleryLayout.astro";
const games = (await getCollection("games", (game) => !game.data.isDraft)).sort(
(a, b) => getUnixTime(b.data.pubDate) - getUnixTime(a.data.pubDate),
(a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime(),
);
---
@ -14,26 +12,23 @@ const games = (await getCollection("games", (game) => !game.data.isDraft)).sort(
<meta slot="head-description" content="Bad Manners || A game that I've gone and done." property="og:description" />
<h1 class="m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">Games</h1>
<p class="my-4">A game that I've gone and done.</p>
<ul class="my-6 flex flex-wrap justify-center gap-4 text-center md:justify-normal items-start">
<ul class="my-6 flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
{
games.map((game) => (
<li>
<a class="text-link hover:underline focus:underline" href={`/games/${game.slug}`}>
{game.data.thumbnail ? (
<div class="max-w-[288px] aspect-[630/500] flex justify-center">
<Image
class="m-auto"
src={game.data.thumbnail}
alt={`Thumbnail for ${game.data.title}`}
width={288}
/>
<div class="flex aspect-[630/500] max-w-[288px] justify-center">
<Image class="m-auto" src={game.data.thumbnail} alt={`Thumbnail for ${game.data.title}`} width={288} />
</div>
) : null}
<div class="max-w-[288px] text-sm">
<>
<span>{game.data.title}</span>
<br />
<span class="italic">{formatDate(game.data.pubDate, "MMM d, yyyy", { locale: enUSLocale })}</span>
<span class="italic">
{game.data.pubDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
</span>
</>
</div>
</a>

View file

@ -1,8 +1,6 @@
---
import { type CollectionEntry, getCollection } from "astro:content";
import { Image } from "astro:assets";
import { getUnixTime, format as formatDate } from "date-fns";
import { enUS as enUSLocale } from "date-fns/locale/en-US";
import GalleryLayout from "../layouts/GalleryLayout.astro";
const MAX_ITEMS = 5;
@ -15,25 +13,32 @@ interface LatestItemsEntry {
pubDate: Date;
}
const stories = (await getCollection("stories", (story) => !story.data.isDraft)).sort((a, b) => getUnixTime(b.data.pubDate) - getUnixTime(a.data.pubDate)).slice(0, MAX_ITEMS);
const games = (await getCollection("games", (game) => !game.data.isDraft)).sort((a, b) => getUnixTime(b.data.pubDate) - getUnixTime(a.data.pubDate)).slice(0, MAX_ITEMS);
const stories = (await getCollection("stories", (story) => !story.data.isDraft))
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
.slice(0, MAX_ITEMS);
const games = (await getCollection("games", (game) => !game.data.isDraft))
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
.slice(0, MAX_ITEMS);
const latestItems: LatestItemsEntry[] = [
stories.map<LatestItemsEntry>(story => ({
stories.map<LatestItemsEntry>((story) => ({
type: "Story",
thumbnail: story.data.thumbnail,
href: `/stories/${story.slug}`,
title: story.data.title,
pubDate: story.data.pubDate,
})),
games.map<LatestItemsEntry>(game => ({
games.map<LatestItemsEntry>((game) => ({
type: "Game",
thumbnail: game.data.thumbnail,
href: `/games/${game.slug}`,
title: game.data.title,
pubDate: game.data.pubDate,
})),
].flat().sort((a, b) => getUnixTime(b.pubDate) - getUnixTime(a.pubDate)).slice(0, MAX_ITEMS);
]
.flat()
.sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime())
.slice(0, MAX_ITEMS);
---
<GalleryLayout pageTitle="Gallery">
@ -54,25 +59,23 @@ const latestItems: LatestItemsEntry[] = [
</p>
<section class="my-2" aria-labelledby="latest-uploads">
<h2 id="latest-uploads" class="p-2 text-xl font-semibold text-stone-800 dark:text-stone-100">Latest uploads</h2>
<ul class="flex flex-wrap justify-center gap-4 text-center md:justify-normal items-start">
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
{
latestItems.map((entry) => (
<li class="break-inside-avoid">
<a class="text-link hover:underline focus:underline" href={entry.href}>
{entry.thumbnail ? (
<div class="max-w-[192px] aspect-square flex justify-center">
<Image
class="m-auto"
src={entry.thumbnail}
alt={`Thumbnail for ${entry.title}`}
width={192}
/>
<div class="flex aspect-square max-w-[192px] justify-center">
<Image class="m-auto" src={entry.thumbnail} alt={`Thumbnail for ${entry.title}`} width={192} />
</div>
) : null}
<div class="max-w-[192px] text-sm">
<span>{entry.title}</span>
<br />
<span class="italic">{entry.type} &ndash; {formatDate(entry.pubDate, "MMM d, yyyy", { locale: enUSLocale })}</span>
<span class="italic">
{entry.type} &ndash;{" "}
{entry.pubDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
</span>
</div>
</a>
</li>

View file

@ -2,14 +2,12 @@
import type { GetStaticPaths, Page } from "astro";
import { Image } from "astro:assets";
import { getCollection } from "astro:content";
import { getUnixTime, format as formatDate } from "date-fns";
import { enUS as enUSLocale } from "date-fns/locale/en-US";
import GalleryLayout from "../../layouts/GalleryLayout.astro";
import type { CollectionEntry } from "astro:content";
export const getStaticPaths: GetStaticPaths = async ({ paginate }) => {
const stories = (await getCollection("stories", (story) => !story.data.isDraft)).sort(
(a, b) => getUnixTime(b.data.pubDate) - getUnixTime(a.data.pubDate),
(a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime(),
);
return paginate(stories, { pageSize: 30 });
};
@ -62,13 +60,13 @@ const totalPages = Math.ceil(page.total / page.size);
)
}
</div>
<ul class="flex flex-wrap justify-center gap-4 text-center md:justify-normal items-start">
<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}`}>
{story.data.thumbnail ? (
<div class="max-w-[192px] aspect-square flex justify-center">
<div class="flex aspect-square max-w-[192px] justify-center">
<Image
class="m-auto"
src={story.data.thumbnail}
@ -80,7 +78,9 @@ const totalPages = Math.ceil(page.total / page.size);
<div class="max-w-[192px] text-sm">
<span>{story.data.title}</span>
<br />
<span class="italic">{formatDate(story.data.pubDate, "MMM d, yyyy", { locale: enUSLocale })}</span>
<span class="italic">
{story.data.pubDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
</span>
</div>
</a>
</li>

View file

@ -1,7 +1,7 @@
import { type APIRoute, type GetStaticPaths } from "astro";
import { getCollection, getEntry, type CollectionEntry, getEntries } from "astro:content";
import { marked, type RendererApi } from "marked";
import he from "he";
import { decode as tinyDecode } from "tiny-decode";
import { type Website } from "../../../../../content/config";
const WEBSITE_LIST = ["eka", "furaffinity", "inkbunny", "sofurry", "weasyl"] as const satisfies Website[];
@ -269,7 +269,7 @@ export const GET: APIRoute<Props, Params> = async ({ props: { story }, params: {
const markdownExport: ReadonlyArray<ExportWebsite> = ["weasyl"] as const;
// BBCode exports
if (bbcodeExports.includes(website)) {
storyDescription = he.decode(await marked.use({ renderer: bbcodeRenderer }).parse(storyDescription));
storyDescription = tinyDecode(await marked.use({ renderer: bbcodeRenderer }).parse(storyDescription));
headers["Content-Type"] = "text/plain; charset=utf-8";
// Markdown exports (no-op)
} else if (!markdownExport.includes(website)) {

View file

@ -1,7 +1,6 @@
---
import { getCollection, getEntry } from "astro:content";
import { Image } from "astro:assets";
import { getUnixTime } from "date-fns";
import GalleryLayout from "../../layouts/GalleryLayout.astro";
import mapImage from "../../assets/images/tlotm_map.jpg";
@ -9,10 +8,10 @@ const series = await getEntry("series", "the-lost-of-the-marshes");
const stories = await getCollection("stories", (story) => !story.data.isDraft && story.data.series?.id === series.id);
const mainChapters = stories
.filter((story) => story.slug.startsWith("the-lost-of-the-marshes/chapter-"))
.sort((a, b) => getUnixTime(a.data.pubDate) - getUnixTime(b.data.pubDate));
.sort((a, b) => a.data.pubDate.getTime() - b.data.pubDate.getTime());
const bonusChapters = stories
.filter((story) => story.slug.startsWith("the-lost-of-the-marshes/bonus-"))
.sort((a, b) => getUnixTime(a.data.pubDate) - getUnixTime(b.data.pubDate));
.sort((a, b) => a.data.pubDate.getTime() - b.data.pubDate.getTime());
const mainChaptersWithSummaries = mainChapters.filter((story) => story.data.summary);
---

View file

@ -3,7 +3,6 @@ import type { GetStaticPaths } from "astro";
import { Image } from "astro:assets";
import { type CollectionEntry, getCollection } from "astro:content";
import { slug } from "github-slugger";
import { getUnixTime } from "date-fns";
import GalleryLayout from "../../layouts/GalleryLayout.astro";
export const getStaticPaths: GetStaticPaths = async () => {
@ -27,10 +26,10 @@ export const getStaticPaths: GetStaticPaths = async () => {
tag,
stories: stories
.filter((story) => !story.data.isDraft && story.data.tags.includes(tag))
.sort((a, b) => getUnixTime(b.data.pubDate!) - getUnixTime(a.data.pubDate!)),
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime()),
games: games
.filter((game) => !game.data.isDraft && game.data.tags.includes(tag))
.sort((a, b) => getUnixTime(b.data.pubDate) - getUnixTime(a.data.pubDate)),
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime()),
},
}));
};
@ -69,12 +68,12 @@ if (count == 1) {
<h2 id="content-stories" class="p-2 text-xl font-semibold text-stone-800 dark:text-stone-100">
Stories
</h2>
<ul class="flex flex-wrap justify-center gap-4 text-center md:justify-normal items-start">
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
{stories.map((story) => (
<li class="break-inside-avoid">
<a class="text-link hover:underline focus:underline" href={`/stories/${story.slug}`}>
{story.data.thumbnail ? (
<div class="max-w-[192px] aspect-square flex justify-center">
<div class="flex aspect-square max-w-[192px] justify-center">
<Image
class="m-auto"
src={story.data.thumbnail}
@ -97,19 +96,19 @@ if (count == 1) {
<h2 id="content-games" class="p-2 text-xl font-semibold text-stone-800 dark:text-stone-100">
Games
</h2>
<ul class="flex flex-wrap justify-center gap-4 text-center md:justify-normal items-start">
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
{games.map((game) => (
<li class="break-inside-avoid">
<a class="text-link hover:underline focus:underline" href={`/games/${game.slug}`}>
{game.data.thumbnail ? (
<div class="max-w-[192px] aspect-[630/500] flex justify-center">
<Image
class="m-auto"
src={game.data.thumbnail}
alt={`Thumbnail for ${game.data.title}`}
width={192}
/>
</div>
<div class="flex aspect-[630/500] max-w-[192px] justify-center">
<Image
class="m-auto"
src={game.data.thumbnail}
alt={`Thumbnail for ${game.data.title}`}
width={192}
/>
</div>
) : null}
<div class="max-w-48 text-sm">{game.data.title}</div>
</a>