Improve feed items

This commit is contained in:
Bad Manners 2024-04-03 20:05:25 -03:00
parent e859109ade
commit 568b7709ec
5 changed files with 74 additions and 44 deletions

View file

@ -16,10 +16,6 @@ export const UI_STRINGS: Record<string, TranslationRecord> = {
: `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`,
tok: (names: string[]) => names.join(" en "),
},
"export_story/warnings": {
eng: (wordCount: number | string, contentWarning: string) => `*Word count: ${wordCount}. ${contentWarning}*`,
tok: (_wordCount: number | string, contentWarning: string) => `*${contentWarning}*`,
},
"export_story/writing": {
eng: (authorsList: string[]) => `Writing: ${authorsList.join(" ")}`,
tok: (authorsList: string[]) => `lipu ni li tan jan ni: ${authorsList.join(" en ")}`,
@ -45,9 +41,9 @@ export const UI_STRINGS: Record<string, TranslationRecord> = {
eng: "Toggle dark mode",
tok: "o ante e kule lipu",
},
"story/word_count": {
eng: (wordCount: string | number) => `Word count: ${wordCount}.`,
tok: "",
"story/warnings": {
eng: (wordCount: number | string, contentWarning: string) => `Word count: ${wordCount}. ${contentWarning}`,
tok: (_wordCount: number | string, contentWarning: string) => `${contentWarning}`,
},
"story/publish_date": {
eng: (date: string) => date,
@ -99,7 +95,7 @@ export const UI_STRINGS: Record<string, TranslationRecord> = {
eng: (owner: string, charactersList: string[]) =>
charactersList.length == 1
? `${charactersList[0]} is © ${owner}`
: `${(UI_STRINGS["util/join_names"]!["eng"] as (arg: string[]) => string)(charactersList)} are © ${owner}`,
: `${(UI_STRINGS["util/join_names"]!.eng as (arg: string[]) => string)(charactersList)} are © ${owner}`,
},
"characters/all_characters_are_copyrighted_by": {
eng: (owner: string) => `All characters are © ${owner}`,

View file

@ -199,8 +199,7 @@ const thumbnail =
}
<div id="content-warning">
<p>
{t(props.lang, "story/word_count", props.wordCount)}
{props.contentWarning}
{t(props.lang, "story/warnings", props.wordCount, props.contentWarning.trim())}
</p>
</div>
</section>

View file

@ -235,7 +235,7 @@ export const GET: APIRoute<Props, Params> = async ({ props: { story }, site }) =
const storyDescription = (
[
story.data.description,
t(lang, "export_story/warnings", story.data.wordCount, story.data.contentWarning.trim()),
`*${t(lang, "story/warnings", story.data.wordCount, story.data.contentWarning.trim())}*`,
t(
lang,
"export_story/writing",

View file

@ -23,10 +23,10 @@ const getLinkForUser = (user: CollectionEntry<"users">, lang: Lang) => {
const userName = user.data.nameLang[lang] || user.data.name;
if (user.data.preferredLink) {
const link = user.data.links[user.data.preferredLink]!;
return `<a href="${typeof link === "string" ? link : link[0]}">${userName}</a>`
return `<a href="${typeof link === "string" ? link : link[0]}">${userName}</a>`;
}
return userName;
}
};
export const GET: APIRoute = async ({ site }) => {
const stories = (await getCollection("stories", (story) => !story.data.isDraft))
@ -42,37 +42,71 @@ export const GET: APIRoute = async ({ site }) => {
description: "Stories, games, and (possibly) more by Bad Manners",
site: site as URL,
items: [
await Promise.all(stories.map<Promise<FeedItem>>(async ({ data, slug, body }) => ({
title: `New story! "${data.title}"`,
pubDate: toNoonUTCDate(data.pubDate),
link: `/stories/${slug}`,
description:
`Word count: ${data.wordCount}. ${data.contentWarning} ${data.descriptionPlaintext || data.description}`
await Promise.all(
stories.map<Promise<FeedItem>>(async ({ data, slug, body }) => ({
title: `New story! "${data.title}"`,
pubDate: toNoonUTCDate(data.pubDate),
link: `/stories/${slug}`,
description:
`${t(data.lang, "story/warnings", data.wordCount, data.contentWarning.trim())} ${data.descriptionPlaintext || data.description}`
.replaceAll(/[\n ]+/g, " ")
.trim(),
categories: ["story"],
content: sanitizeHtml(
`<h1>${data.title}</h1>` +
`<p>${t(
data.lang,
"story/authors",
[data.authors].flatMap((authorArray) => {
if (!Array.isArray(authorArray)) {
authorArray = [authorArray];
}
return authorArray.map((author) =>
getLinkForUser(users.find((user) => user.id === author.id)!, data.lang),
);
}),
)}</p>` +
(data.requester
? `<p>${t(data.lang, "export_story/request_for", getLinkForUser(users.find((user) => user.id === data.requester!.id)!, data.lang))}</p>`
: "") +
(data.commissioner
? `<p>${t(data.lang, "export_story/commissioned_by", getLinkForUser(users.find((user) => user.id === data.commissioner!.id)!, data.lang))}</p>`
: "") +
`<hr><p><em>${t(data.lang, "story/warnings", data.wordCount, data.contentWarning.trim())}</em></p>` +
`<hr>${tinyDecode(await marked(body))}` +
`<hr>${tinyDecode(await marked(data.description))}`,
),
})),
),
await Promise.all(
games.map<Promise<FeedItem>>(async ({ data, slug, body }) => ({
title: `New game! "${data.title}"`,
pubDate: toNoonUTCDate(data.pubDate),
link: `/games/${slug}`,
description: `${data.contentWarning} ${data.descriptionPlaintext || data.description}`
.replaceAll(/[\n ]+/g, " ")
.trim(),
categories: ["story"],
content: sanitizeHtml(`<h1>${data.title}</h1><p>${t(data.lang, "story/authors", [data.authors].flatMap((authorArray => {
if (!Array.isArray(authorArray)) {
authorArray = [authorArray]
}
return authorArray.map(author => getLinkForUser(users.find(user => user.id === author.id)!, data.lang));
})))}</p>${data.requester ? `<p>${t(data.lang, "export_story/request_for", getLinkForUser(users.find(user => user.id === data.requester!.id)!, data.lang))}</p>` : ""}${data.commissioner ? `<p>${t(data.lang, "export_story/commissioned_by", getLinkForUser(users.find(user => user.id === data.commissioner!.id)!, data.lang))}</p>` : ""}<hr>${tinyDecode(await marked(body))}`),
}))),
await Promise.all(games.map<Promise<FeedItem>>(async ({ data, slug, body }) => ({
title: `New game! "${data.title}"`,
pubDate: toNoonUTCDate(data.pubDate),
link: `/games/${slug}`,
description: `${data.contentWarning} ${data.descriptionPlaintext || data.description}`
.replaceAll(/[\n ]+/g, " ")
.trim(),
categories: ["game"],
content: sanitizeHtml(`<h1>${data.title}</h1><p>${t(data.lang, "story/authors", [data.authors].flatMap((authorArray => {
if (!Array.isArray(authorArray)) {
authorArray = [authorArray]
}
return authorArray.map(author => getLinkForUser(users.find(user => user.id === author.id)!, data.lang));
})))}</p><hr>${tinyDecode(await marked(body))}`),
}))),
categories: ["game"],
content: sanitizeHtml(
`<h1>${data.title}</h1>` +
`<p>${t(
data.lang,
"story/authors",
[data.authors].flatMap((authorArray) => {
if (!Array.isArray(authorArray)) {
authorArray = [authorArray];
}
return authorArray.map((author) =>
getLinkForUser(users.find((user) => user.id === author.id)!, data.lang),
);
}),
)}</p>` +
`<hr><p><em>${data.contentWarning.trim()}</em></p>` +
`<hr>${tinyDecode(await marked(body))}` +
`<hr>${tinyDecode(await marked(data.description))}`,
),
})),
),
]
.flat()
.sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime())

View file

@ -1,13 +1,14 @@
import type { APIRoute } from "astro";
const licenses = `The briefcase logo and any unattributed characters are copyrighted and trademarked by me.
const licenses = `
The briefcase logo and any unattributed characters are copyrighted and trademarked by me.
The Noto Sans and Noto Serif typefaces are copyrighted to the Noto Project Authors and distributed under the SIL Open Font License v1.1.
The generic SVG icons were created by Font Awesome and are distributed under the CC BY 4.0 license.
All third-party trademarks belong to their respective owners, and I'm not affiliated with any of them.
`;
`.trim();
export const GET: APIRoute = () => {
return new Response(licenses, {