Improvements to a11y and scripts
This commit is contained in:
parent
a335aff2d3
commit
d022fab5d6
17 changed files with 384 additions and 214 deletions
|
|
@ -78,7 +78,7 @@ export const GET: APIRoute<Props, Params> = async ({ props: { story }, site }) =
|
|||
commissionersList.map((commissioner) => u(commissioner)),
|
||||
),
|
||||
...copyrightedCharacters.map(({ user, characters }) =>
|
||||
t(lang, "characters/characters_are_copyrighted_by", u(user), characters[0] == "" ? [] : characters),
|
||||
t(lang, "characters/characters_are_copyrighted_by", u(user), characters[0] === "" ? [] : characters),
|
||||
),
|
||||
].reduce(async (promise, data) => {
|
||||
if (!data) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { Image } from "astro:assets";
|
||||
import { getCollection, getEntries, type CollectionEntry } from "astro:content";
|
||||
import GalleryLayout from "../layouts/GalleryLayout.astro";
|
||||
import { DEFAULT_LANG, t } from "../i18n";
|
||||
import { t } from "../i18n";
|
||||
import UserComponent from "../components/UserComponent.astro";
|
||||
|
||||
type GameWithPubDate = CollectionEntry<"games"> & { data: { pubDate: Date } };
|
||||
|
|
@ -24,7 +24,7 @@ const games = await Promise.all(
|
|||
<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">
|
||||
<li class="h-entry" lang={game.data.lang}>
|
||||
<a
|
||||
class="u-url text-link hover:underline focus:underline"
|
||||
href={`/games/${game.slug}`}
|
||||
|
|
@ -42,17 +42,31 @@ const games = await Promise.all(
|
|||
</div>
|
||||
) : null}
|
||||
<div class="max-w-[288px] text-sm">
|
||||
<span class="p-name">{game.data.title}</span>
|
||||
<span class="p-name" aria-label="Title">
|
||||
{game.data.title}
|
||||
</span>
|
||||
<br />
|
||||
<time class="dt-published italic" datetime={game.data.pubDate.toISOString().slice(0, 10)}>
|
||||
<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 style={{ display: "none" }}>
|
||||
{game.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={DEFAULT_LANG} />
|
||||
))}
|
||||
<div class="sr-only">
|
||||
<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>
|
||||
<div aria-label="Authors">
|
||||
{game.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={game.data.lang} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { ImageMetadata } from "astro";
|
|||
import { type CollectionEntry, type CollectionKey, getCollection, getEntries } from "astro:content";
|
||||
import { Image } from "astro:assets";
|
||||
import GalleryLayout from "../layouts/GalleryLayout.astro";
|
||||
import { DEFAULT_LANG, t, type Lang } from "../i18n";
|
||||
import { t, type Lang } from "../i18n";
|
||||
import UserComponent from "../components/UserComponent.astro";
|
||||
|
||||
const MAX_ITEMS = 10;
|
||||
|
|
@ -60,7 +60,7 @@ const latestItems: LatestItemsEntry[] = await Promise.all(
|
|||
href: `/games/${game.slug}`,
|
||||
title: game.data.title,
|
||||
authors: await getEntries(game.data.authors),
|
||||
lang: DEFAULT_LANG,
|
||||
lang: game.data.lang,
|
||||
altText: t(game.data.lang, "game/warnings", game.data.platforms, game.data.contentWarning),
|
||||
pubDate: game.data.pubDate,
|
||||
}) satisfies LatestItemsEntry,
|
||||
|
|
@ -99,7 +99,7 @@ const latestItems: LatestItemsEntry[] = await Promise.all(
|
|||
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
|
||||
{
|
||||
latestItems.map((entry) => (
|
||||
<li class="h-entry break-inside-avoid">
|
||||
<li class="h-entry break-inside-avoid" lang={entry.lang}>
|
||||
<a class="u-url text-link hover:underline focus:underline" href={entry.href} title={entry.altText}>
|
||||
{entry.thumbnail ? (
|
||||
<div class="flex aspect-square max-w-[192px] justify-center">
|
||||
|
|
@ -113,20 +113,34 @@ const latestItems: LatestItemsEntry[] = await Promise.all(
|
|||
</div>
|
||||
) : null}
|
||||
<div class="max-w-[192px] text-sm">
|
||||
<span class="p-name">{entry.title}</span>
|
||||
<span class="p-name" aria-label="Title">
|
||||
{entry.title}
|
||||
</span>
|
||||
<br />
|
||||
<span class="italic">
|
||||
<span class="p-category">{entry.type}</span> –{" "}
|
||||
<time class="dt-published" datetime={entry.pubDate.toISOString().slice(0, 10)}>
|
||||
<span class="p-category" aria-label="Category">
|
||||
{entry.type}
|
||||
</span>{" "}
|
||||
–{" "}
|
||||
<time
|
||||
class="dt-published"
|
||||
datetime={entry.pubDate.toISOString().slice(0, 10)}
|
||||
aria-label="Publish date"
|
||||
>
|
||||
{entry.pubDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
|
||||
</time>
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<div style={{ display: "none" }}>
|
||||
{entry.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={entry.lang} />
|
||||
))}
|
||||
<div class="sr-only">
|
||||
<p class="p-summary" aria-label="Summary">
|
||||
{entry.altText}
|
||||
</p>
|
||||
<div aria-label="Authors">
|
||||
{entry.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={entry.lang} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const totalPages = Math.ceil(page.total / page.size);
|
|||
<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
|
||||
page.start === page.end
|
||||
? `Displaying story #${page.start + 1}`
|
||||
: `Displaying stories #${page.start + 1}–${page.end + 1}`
|
||||
} / {page.total}
|
||||
|
|
@ -53,7 +53,7 @@ const totalPages = Math.ceil(page.total / page.size);
|
|||
[...Array(totalPages).keys()]
|
||||
.map((p) => p + 1)
|
||||
.map((p) =>
|
||||
p == page.currentPage ? (
|
||||
p === 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}
|
||||
</span>
|
||||
|
|
@ -78,7 +78,7 @@ const totalPages = Math.ceil(page.total / page.size);
|
|||
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
|
||||
{
|
||||
page.data.map((story, i) => (
|
||||
<li class="h-entry break-inside-avoid">
|
||||
<li class="h-entry break-inside-avoid" lang={story.data.lang}>
|
||||
<a
|
||||
class="u-url text-link hover:underline focus:underline"
|
||||
href={`/stories/${story.slug}`}
|
||||
|
|
@ -96,17 +96,31 @@ const totalPages = Math.ceil(page.total / page.size);
|
|||
</div>
|
||||
) : null}
|
||||
<div class="max-w-[192px] text-sm">
|
||||
<span class="p-name">{story.data.title}</span>
|
||||
<span class="p-name" aria-label="Title">
|
||||
{story.data.title}
|
||||
</span>
|
||||
<br />
|
||||
<time class="italic" datetime={story.data.pubDate.toISOString().slice(0, 10)}>
|
||||
<time
|
||||
class="dt-published italic"
|
||||
datetime={story.data.pubDate.toISOString().slice(0, 10)}
|
||||
aria-label="Publish date"
|
||||
>
|
||||
{story.data.pubDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
|
||||
</time>
|
||||
</div>
|
||||
</a>
|
||||
<div style={{ display: "none" }}>
|
||||
{story.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={story.data.lang} />
|
||||
))}
|
||||
<div class="sr-only">
|
||||
<p class="p-category" aria-label="Category">
|
||||
Story
|
||||
</p>
|
||||
<p class="p-summary" aria-label="Summary">
|
||||
{t(story.data.lang, "story/warnings", story.data.wordCount, story.data.contentWarning)}
|
||||
</p>
|
||||
<div aria-label="Authors">
|
||||
{story.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={story.data.lang} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))
|
||||
|
|
@ -124,7 +138,7 @@ const totalPages = Math.ceil(page.total / page.size);
|
|||
[...Array(totalPages).keys()]
|
||||
.map((p) => p + 1)
|
||||
.map((p) =>
|
||||
p == page.currentPage ? (
|
||||
p === 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}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ uncategorizedTagsSet.forEach((tag) => draftOnlyTagsSet.delete(tag));
|
|||
const uniqueSlugs = new Set<string>();
|
||||
const categorizedTags = tagCategories
|
||||
.sort((a, b) => {
|
||||
if (a.data.index == b.data.index) {
|
||||
if (a.data.index === b.data.index) {
|
||||
throw new Error(`Found tag categories with same index value ${a.data.index} ("${a.id}", "${b.id}")`);
|
||||
}
|
||||
return a.data.index - b.data.index;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
---
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { Image } from "astro:assets";
|
||||
import { type CollectionEntry, type CollectionKey, getCollection } from "astro:content";
|
||||
import { type CollectionEntry, type CollectionKey, getCollection, getEntries } from "astro:content";
|
||||
import { Markdown } from "@astropub/md";
|
||||
import { slug } from "github-slugger";
|
||||
import GalleryLayout from "../../layouts/GalleryLayout.astro";
|
||||
import Prose from "../../components/Prose.astro";
|
||||
import { t, DEFAULT_LANG } from "../../i18n";
|
||||
import { qualifyLocalURLsInMarkdown } from "../../utils/qualify_local_urls_in_markdown";
|
||||
import UserComponent from "../../components/UserComponent.astro";
|
||||
|
||||
type EntryWithPubDate<C extends CollectionKey> = CollectionEntry<C> & { data: { pubDate: Date } };
|
||||
|
||||
|
|
@ -15,8 +16,8 @@ type Props = {
|
|||
tag: string;
|
||||
description?: string;
|
||||
related?: string[];
|
||||
stories: EntryWithPubDate<"stories">[];
|
||||
games: EntryWithPubDate<"games">[];
|
||||
stories: (EntryWithPubDate<"stories"> & { authors: CollectionEntry<"users">[] })[];
|
||||
games: (EntryWithPubDate<"games"> & { authors: CollectionEntry<"users">[] })[];
|
||||
};
|
||||
|
||||
type Params = {
|
||||
|
|
@ -46,7 +47,7 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
|||
(acc, category) => {
|
||||
category.data.tags.forEach(({ name, description, related }) => {
|
||||
related = related.filter((relatedTag) => {
|
||||
if (relatedTag == name) {
|
||||
if (relatedTag === name) {
|
||||
console.warn(`WARNING: Tag "${name}" should not have itself as a related tag; removing...`);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -66,26 +67,42 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
|||
},
|
||||
{} as Record<string, { description?: string; related?: string[] }>,
|
||||
);
|
||||
return [...tags]
|
||||
.filter((tag) => !seriesTags.has(tag))
|
||||
.map((tag) => ({
|
||||
params: { slug: slug(tag) } satisfies Params,
|
||||
props: {
|
||||
tag,
|
||||
description: tagDescriptions[tag]?.description,
|
||||
related: tagDescriptions[tag]?.related,
|
||||
stories: (
|
||||
stories.filter(
|
||||
(story) => !story.data.isDraft && story.data.pubDate && story.data.tags.includes(tag),
|
||||
) as EntryWithPubDate<"stories">[]
|
||||
).sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime()),
|
||||
games: (
|
||||
games.filter(
|
||||
(game) => !game.data.isDraft && game.data.pubDate && game.data.tags.includes(tag),
|
||||
) as EntryWithPubDate<"games">[]
|
||||
).sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime()),
|
||||
} satisfies Props,
|
||||
}));
|
||||
return await Promise.all(
|
||||
[...tags]
|
||||
.filter((tag) => !seriesTags.has(tag))
|
||||
.map(async (tag) => ({
|
||||
params: { slug: slug(tag) } satisfies Params,
|
||||
props: {
|
||||
tag,
|
||||
description: tagDescriptions[tag]?.description,
|
||||
related: tagDescriptions[tag]?.related,
|
||||
stories: await Promise.all(
|
||||
(
|
||||
stories.filter(
|
||||
(story) => !story.data.isDraft && story.data.pubDate && story.data.tags.includes(tag),
|
||||
) as EntryWithPubDate<"stories">[]
|
||||
)
|
||||
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
|
||||
.map(async (story) => ({
|
||||
...story,
|
||||
authors: await getEntries(story.data.authors),
|
||||
})),
|
||||
),
|
||||
games: await Promise.all(
|
||||
(
|
||||
games.filter(
|
||||
(game) => !game.data.isDraft && game.data.pubDate && game.data.tags.includes(tag),
|
||||
) as EntryWithPubDate<"games">[]
|
||||
)
|
||||
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
|
||||
.map(async (game) => ({
|
||||
...game,
|
||||
authors: await getEntries(game.data.authors),
|
||||
})),
|
||||
),
|
||||
} satisfies Props,
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
const { props } = Astro;
|
||||
|
|
@ -130,7 +147,7 @@ const totalWorksWithTag = t(
|
|||
</h2>
|
||||
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
|
||||
{props.stories.map((story) => (
|
||||
<li class="h-entry break-inside-avoid">
|
||||
<li class="h-entry break-inside-avoid" lang={story.data.lang}>
|
||||
<a
|
||||
class="u-url text-link hover:underline focus:underline"
|
||||
href={`/stories/${story.slug}`}
|
||||
|
|
@ -147,9 +164,15 @@ const totalWorksWithTag = t(
|
|||
</div>
|
||||
) : null}
|
||||
<div class="max-w-[192px] text-sm">
|
||||
<span class="p-name">{story.data.title}</span>
|
||||
<span class="p-name" aria-label="Title">
|
||||
{story.data.title}
|
||||
</span>
|
||||
<br />
|
||||
<time class="dt-published italic" datetime={story.data.pubDate.toISOString().slice(0, 10)}>
|
||||
<time
|
||||
class="dt-published italic"
|
||||
datetime={story.data.pubDate.toISOString().slice(0, 10)}
|
||||
aria-label="Publish date"
|
||||
>
|
||||
{story.data.pubDate.toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
|
|
@ -158,6 +181,19 @@ const totalWorksWithTag = t(
|
|||
</time>
|
||||
</div>
|
||||
</a>
|
||||
<div class="sr-only">
|
||||
<p class="p-category" aria-label="Category">
|
||||
Story
|
||||
</p>
|
||||
<p class="p-summary" aria-label="Summary">
|
||||
{t(story.data.lang, "story/warnings", story.data.wordCount, story.data.contentWarning)}
|
||||
</p>
|
||||
<div aria-label="Authors">
|
||||
{story.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={story.data.lang} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
@ -172,7 +208,7 @@ const totalWorksWithTag = t(
|
|||
</h2>
|
||||
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
|
||||
{props.games.map((game) => (
|
||||
<li class="h-entry break-inside-avoid">
|
||||
<li class="h-entry break-inside-avoid" lang={game.data.lang}>
|
||||
<a
|
||||
class="u-url text-link hover:underline focus:underline"
|
||||
href={`/games/${game.slug}`}
|
||||
|
|
@ -189,13 +225,32 @@ const totalWorksWithTag = t(
|
|||
</div>
|
||||
) : null}
|
||||
<div class="max-w-[192px] text-sm">
|
||||
<span class="p-name">{game.data.title}</span>
|
||||
<span class="p-name" aria-label="Title">
|
||||
{game.data.title}
|
||||
</span>
|
||||
<br />
|
||||
<time class="dt-published italic" datetime={game.data.pubDate.toISOString().slice(0, 10)}>
|
||||
<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">
|
||||
<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>
|
||||
<div aria-label="Authors">
|
||||
{game.authors.map((author) => (
|
||||
<UserComponent rel="author" class="p-author" user={author} lang={game.data.lang} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue