Add Mastodon links to new stories, add title texts, and improve tags
- Added Mastodon links to "Woofer Exploration" and "Rose's Binge" - Add title texts to stories and games thumbnails on index, stories, games, and tag pages - Add descriptions and related tags to tag pages
This commit is contained in:
parent
efcfce1e06
commit
a713adc1ec
34 changed files with 493 additions and 239 deletions
|
|
@ -1,13 +1,12 @@
|
|||
import type { APIRoute, GetStaticPaths } from "astro";
|
||||
import { getCollection, getEntry, type CollectionEntry, getEntries } from "astro:content";
|
||||
import { marked, type RendererApi } from "marked";
|
||||
import { decode as tinyDecode } from "tiny-decode";
|
||||
import type { Lang, Website } from "../../../content/config";
|
||||
import { t } from "../../../i18n";
|
||||
import { formatCopyrightedCharacters } from "../../../utils/format_copyrighted_characters";
|
||||
import { markdownToBbcode } from "../../../utils/markdown_to_bbcode";
|
||||
|
||||
interface ExportWebsiteInfo {
|
||||
website: string;
|
||||
website: Website;
|
||||
exportFormat: "bbcode" | "markdown";
|
||||
}
|
||||
|
||||
|
|
@ -21,37 +20,6 @@ const WEBSITE_LIST = [
|
|||
|
||||
type ExportWebsiteName = typeof WEBSITE_LIST extends ReadonlyArray<{ website: infer K }> ? K : never;
|
||||
|
||||
//type ExportWebsiteName = typeof WEBSITE_LIST extends ReadonlyArray<[infer K, DescriptionExportFormat]> ? K : never;
|
||||
|
||||
const bbcodeRenderer: RendererApi = {
|
||||
strong: (text) => `[b]${text}[/b]`,
|
||||
em: (text) => `[i]${text}[/i]`,
|
||||
codespan: (code) => code,
|
||||
br: () => `\n\n`,
|
||||
link: (href, _, text) => `[url=${href}]${text}[/url]`,
|
||||
image: (href) => `[img]${href}[/img]`,
|
||||
text: (text) => text,
|
||||
paragraph: (text) => `\n${text}\n`,
|
||||
list: (body, ordered) => (ordered ? `\n[ol]\n${body}[/ol]\n` : `\n[ul]\n${body}[/ul]\n`),
|
||||
listitem: (text) => `[li]${text}[/li]\n`,
|
||||
blockquote: (quote) => `\n[quote]${quote}[/quote]\n`,
|
||||
code: (code) => `\n[code]${code}[/code]\n`,
|
||||
heading: (heading) => `\n${heading}\n`,
|
||||
table: (header, body) => `\n[table]\n${header}${body}[/table]\n`,
|
||||
tablerow: (content) => `[tr]\n${content}[/tr]\n`,
|
||||
tablecell: (content, { header }) => (header ? `[th]${content}[/th]\n` : `[td]${content}[/td]\n`),
|
||||
hr: () => `\n===\n`,
|
||||
del: () => {
|
||||
throw new Error("Not supported by bbcodeRenderer: del");
|
||||
},
|
||||
html: () => {
|
||||
throw new Error("Not supported by bbcodeRenderer: html");
|
||||
},
|
||||
checkbox: () => {
|
||||
throw new Error("Not supported by bbcodeRenderer: checkbox");
|
||||
},
|
||||
};
|
||||
|
||||
function getUsernameForWebsite(user: CollectionEntry<"users">, website: Website): string {
|
||||
const link = user.data.links[website];
|
||||
if (link) {
|
||||
|
|
@ -147,7 +115,7 @@ function getLinkForUser(user: CollectionEntry<"users">, website: ExportWebsiteNa
|
|||
if ("weasyl" in user.data.links) {
|
||||
return `<!~${getUsernameForWebsite(user, "weasyl").replaceAll(" ", "")}>`;
|
||||
} else if (isPreferredWebsite(user, "furaffinity")) {
|
||||
return `<fa:${getUsernameForWebsite(user, "furaffinity")}>`;
|
||||
return `<fa:${getUsernameForWebsite(user, "furaffinity").replaceAll("_", "")}>`;
|
||||
} else if (isPreferredWebsite(user, "inkbunny")) {
|
||||
return `<ib:${getUsernameForWebsite(user, "inkbunny")}>`;
|
||||
} else if (isPreferredWebsite(user, "sofurry")) {
|
||||
|
|
@ -220,47 +188,40 @@ export const GET: APIRoute<Props, Params> = async ({ props: { story }, site }) =
|
|||
const anonymousUser = await getEntry("users", "anonymous");
|
||||
const anonymousFallback = getNameForUser(anonymousUser, anonymousUser, lang);
|
||||
|
||||
const description: Record<ExportWebsiteName, string> = Object.fromEntries(
|
||||
await Promise.all(
|
||||
WEBSITE_LIST.map(async ({ website, exportFormat }) => {
|
||||
const u = (user: CollectionEntry<"users">) => getLinkForUser(user, website, anonymousFallback);
|
||||
const storyDescription = (
|
||||
[
|
||||
story.data.description,
|
||||
`*${t(lang, "story/warnings", story.data.wordCount || "???", story.data.contentWarning.trim())}*`,
|
||||
t(
|
||||
lang,
|
||||
"export_story/writing",
|
||||
authorsList.map((author) => u(author)),
|
||||
),
|
||||
requester && t(lang, "export_story/request_for", u(requester)),
|
||||
commissioner && t(lang, "export_story/commissioned_by", u(commissioner)),
|
||||
...copyrightedCharacters.map(([user, characterList]) =>
|
||||
characterList[0] == ""
|
||||
? t(lang, "characters/all_characters_are_copyrighted_by", u(user))
|
||||
: t(lang, "characters/characters_are_copyrighted_by", u(user), characterList),
|
||||
),
|
||||
].filter((data) => data) as string[]
|
||||
)
|
||||
.join("\n\n")
|
||||
.replaceAll(
|
||||
/\[([^\]]+)\]\((\/[^\)]+)\)/g,
|
||||
(_, group1, group2) => `[${group1}](${new URL(group2, site).toString()})`,
|
||||
);
|
||||
if (exportFormat === "bbcode") {
|
||||
return [
|
||||
website,
|
||||
tinyDecode(await marked.use({ renderer: bbcodeRenderer }).parse(storyDescription))
|
||||
.replaceAll(/\n\n\n+/g, "\n\n")
|
||||
.trim(),
|
||||
];
|
||||
}
|
||||
if (exportFormat === "markdown") {
|
||||
return [website, storyDescription.replaceAll(/\n\n\n+/g, "\n\n").trim()];
|
||||
}
|
||||
throw new Error(`Unhandled ExportFormat "${exportFormat}"`);
|
||||
}),
|
||||
),
|
||||
const description = Object.fromEntries(
|
||||
WEBSITE_LIST.map<[ExportWebsiteName, string]>(({ website, exportFormat }) => {
|
||||
const u = (user: CollectionEntry<"users">) => getLinkForUser(user, website, anonymousFallback);
|
||||
const storyDescription = (
|
||||
[
|
||||
story.data.description,
|
||||
`*${t(lang, "story/warnings", story.data.wordCount || "???", story.data.contentWarning.trim())}*`,
|
||||
t(
|
||||
lang,
|
||||
"export_story/writing",
|
||||
authorsList.map((author) => u(author)),
|
||||
),
|
||||
requester && t(lang, "export_story/request_for", u(requester)),
|
||||
commissioner && t(lang, "export_story/commissioned_by", u(commissioner)),
|
||||
...copyrightedCharacters.map(([user, characterList]) =>
|
||||
characterList[0] == ""
|
||||
? t(lang, "characters/all_characters_are_copyrighted_by", u(user))
|
||||
: t(lang, "characters/characters_are_copyrighted_by", u(user), characterList),
|
||||
),
|
||||
].filter((data) => data) as string[]
|
||||
)
|
||||
.join("\n\n")
|
||||
.replaceAll(
|
||||
/\[([^\]]+)\]\((\/[^\)]+)\)/g,
|
||||
(_, group1, group2) => `[${group1}](${new URL(group2, site).toString()})`,
|
||||
);
|
||||
if (exportFormat === "bbcode") {
|
||||
return [website, markdownToBbcode(storyDescription).replaceAll(/\n\n\n+/g, "\n\n").trim()];
|
||||
} else if (exportFormat === "markdown") {
|
||||
return [website, storyDescription.replaceAll(/\n\n\n+/g, "\n\n").trim()];
|
||||
} else {
|
||||
throw new Error(`Unhandled export format "${exportFormat}"`);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const storyHeader =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue