Final touches to the facelift

This commit is contained in:
Bad Manners 2024-09-07 18:02:53 -03:00
parent 379287af36
commit a2fbf908aa
Signed by: badmanners
GPG key ID: 8C88292CCB075609
19 changed files with 194 additions and 87 deletions

98
package-lock.json generated
View file

@ -18,6 +18,7 @@
"astro-htaccess": "^0.1.2",
"astro-pagefind": "^1.6.0",
"clsx": "^2.1.1",
"fluid-tailwind": "^1.0.3",
"github-slugger": "^2.0.0",
"marked": "^14.0.0",
"pagefind": "^1.1.0",
@ -1601,65 +1602,71 @@
}
},
"node_modules/@pagefind/darwin-arm64": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.1.0.tgz",
"integrity": "sha512-SLsXNLtSilGZjvqis8sX42fBWsWAVkcDh1oerxwqbac84HbiwxpxOC2jm8hRwcR0Z55HPZPWO77XeRix/8GwTg==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.1.1.tgz",
"integrity": "sha512-tZ9tysUmQpFs2EqWG2+E1gc+opDAhSyZSsgKmFzhnWfkK02YHZhvL5XJXEZDqYy3s1FAKhwjTg8XDxneuBlDZQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@pagefind/darwin-x64": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.1.0.tgz",
"integrity": "sha512-QjQSE/L5oS1C8N8GdljGaWtjCBMgMtfrPAoiCmINTu9Y9dp0ggAyXvF8K7Qg3VyIMYJ6v8vg2PN7Z3b+AaAqUA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.1.1.tgz",
"integrity": "sha512-ChohLQ39dLwaxQv0jIQB/SavP3TM5K5ENfDTqIdzLkmfs3+JlzSDyQKcJFjTHYcCzQOZVeieeGq8PdqvLJxJxQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@pagefind/default-ui": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.1.0.tgz",
"integrity": "sha512-+XiAJAK++C64nQcD7s3Prdmd5S92lT05fwjOxm0L1jj80jbL+tmvcqkkFnPpoqhnicIPgcAX/Y5W0HRZnBt35w=="
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.1.1.tgz",
"integrity": "sha512-ZM0zDatWDnac/VGHhQCiM7UgA4ca8jpjA+VfuTJyHJBaxGqZMQnm4WoTz9E0KFcue1Bh9kxpu7uWFZfwpZZk0A==",
"license": "MIT"
},
"node_modules/@pagefind/linux-arm64": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.1.0.tgz",
"integrity": "sha512-8zjYCa2BtNEL7KnXtysPtBELCyv5DSQ4yHeK/nsEq6w4ToAMTBl0K06khqxdSGgjMSwwrxvLzq3so0LC5Q14dA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.1.1.tgz",
"integrity": "sha512-H5P6wDoCoAbdsWp0Zx0DxnLUrwTGWGLu/VI1rcN2CyFdY2EGSvPQsbGBMrseKRNuIrJDFtxHHHyjZ7UbzaM9EA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@pagefind/linux-x64": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.1.0.tgz",
"integrity": "sha512-4lsg6VB7A6PWTwaP8oSmXV4O9H0IHX7AlwTDcfyT+YJo/sPXOVjqycD5cdBgqNLfUk8B9bkWcTDCRmJbHrKeCw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.1.1.tgz",
"integrity": "sha512-yJs7tTYbL2MI3HT+ngs9E1BfUbY9M4/YzA0yEM5xBo4Xl8Yu8Qg2xZTOQ1/F6gwvMrjCUFo8EoACs6LRDhtMrQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@pagefind/windows-x64": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.1.0.tgz",
"integrity": "sha512-OboCM76BcMKT9IoSfZuFhiqMRgTde8x4qDDvKulFmycgiJrlL5WnIqBHJLQxZq+o2KyZpoHF97iwsGAm8c32sQ==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.1.1.tgz",
"integrity": "sha512-b7/qPqgIl+lMzkQ8fJt51SfguB396xbIIR+VZ3YrL2tLuyifDJ1wL5mEm+ddmHxJ2Fki340paPcDan9en5OmAw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
@ -3370,6 +3377,18 @@
"node": ">=8"
}
},
"node_modules/filter-obj": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
"integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==",
"license": "MIT",
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@ -3413,6 +3432,20 @@
"node": ">=8"
}
},
"node_modules/fluid-tailwind": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/fluid-tailwind/-/fluid-tailwind-1.0.3.tgz",
"integrity": "sha512-JhSklHiXUcKnb/PIru1TbyorLD+k0rCIgeAbFwzu1QyQHYDKmKKsKzN7xPisSeGGr7FtYY9S63t+tzddUlxxrQ==",
"license": "MIT",
"dependencies": {
"filter-obj": "^5.1.0",
"map-obj": "^5.0.2",
"picocolors": "^1.0.0"
},
"peerDependencies": {
"tailwindcss": "^3.2.0"
}
},
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@ -4266,6 +4299,18 @@
"optional": true,
"peer": true
},
"node_modules/map-obj": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.2.tgz",
"integrity": "sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==",
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/markdown-table": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
@ -5361,18 +5406,19 @@
}
},
"node_modules/pagefind": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.1.0.tgz",
"integrity": "sha512-1nmj0/vfYcMxNEQj0YDRp6bTVv9hI7HLdPhK/vBBYlrnwjATndQvHyicj5Y7pUHrpCFZpFnLVQXIF829tpFmaw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.1.1.tgz",
"integrity": "sha512-U2YR0dQN5B2fbIXrLtt/UXNS0yWSSYfePaad1KcBPTi0p+zRtsVjwmoPaMQgTks5DnHNbmDxyJUL5TGaLljK3A==",
"license": "MIT",
"bin": {
"pagefind": "lib/runner/bin.cjs"
},
"optionalDependencies": {
"@pagefind/darwin-arm64": "1.1.0",
"@pagefind/darwin-x64": "1.1.0",
"@pagefind/linux-arm64": "1.1.0",
"@pagefind/linux-x64": "1.1.0",
"@pagefind/windows-x64": "1.1.0"
"@pagefind/darwin-arm64": "1.1.1",
"@pagefind/darwin-x64": "1.1.1",
"@pagefind/linux-arm64": "1.1.1",
"@pagefind/linux-x64": "1.1.1",
"@pagefind/windows-x64": "1.1.1"
}
},
"node_modules/parse-latin": {

View file

@ -25,6 +25,7 @@
"astro-htaccess": "^0.1.2",
"astro-pagefind": "^1.6.0",
"clsx": "^2.1.1",
"fluid-tailwind": "^1.0.3",
"github-slugger": "^2.0.0",
"marked": "^14.0.0",
"pagefind": "^1.1.0",

View file

@ -168,10 +168,16 @@ async function exportStory(slug: string, options: { outputDir: string }) {
);
const rtfText = await readFile(join(tempDir, "temp.rtf"), "utf-8");
const rtfStyles = getRTFStyles(rtfText);
await writeFile(
join(outputDir, `${slug}.rtf`),
rtfText.replaceAll(rtfStyles["Preformatted Text"], rtfStyles["Normal"]),
);
if (!rtfStyles["Preformatted Text"]) {
console.warn(`Missing RTF style "Preformatted Text"! Skipping RTF file generation.`);
} else if (!rtfStyles["Normal"]) {
console.warn(`Missing RTF style "Normal"! Skipping RTF file generation.`);
} else {
await writeFile(
join(outputDir, `${slug}.rtf`),
rtfText.replaceAll(rtfStyles["Preformatted Text"], rtfStyles["Normal"]),
);
}
})(),
]);
console.log("Success!");

View file

@ -254,11 +254,11 @@ const { link, instance, user, postId } = Astro.props;
if (comment.in_reply_to_id === post.postId || !(comment.in_reply_to_id in commentMap)) {
commentMap[comment.id] = commentsList.length;
commentsList.push(commentBox);
} else {
const commentsIndex = commentMap[comment.in_reply_to_id];
} else if (commentMap[comment.in_reply_to_id]) {
const commentsIndex = commentMap[comment.in_reply_to_id]!;
commentMap[comment.id] = commentsIndex;
const parentThreadDiv =
commentsList[commentsIndex].querySelector<HTMLElementTagNameMap["div"]>("div[data-comment-thread]")!;
commentsList[commentsIndex]!.querySelector<HTMLElementTagNameMap["div"]>("div[data-comment-thread]")!;
parentThreadDiv.setAttribute("aria-hidden", "false");
parentThreadDiv.appendChild(commentBox);
}

View file

@ -222,6 +222,7 @@ export type GamePlatform = z.infer<typeof platform>;
export type CopyrightedCharacters = z.infer<typeof copyrightedCharacters>;
export type PublishedContent = z.infer<typeof publishedContent>;
export type PostWebsite = keyof PublishedContent["posts"];
export type Posts = PublishedContent["posts"];
// Content collections

View file

@ -13,7 +13,7 @@ const UI_STRINGS = {
tok: (names: string[]) => names.join(" en "),
},
"util/capitalize": {
en: (text: string) => (text.length > 0 ? `${text[0].toUpperCase()}${text.slice(1)}` : ""),
en: (text: string) => (text.length > 0 ? `${text[0]!.toUpperCase()}${text.slice(1)}` : ""),
},
"util/enumerate": {
en: (count: number, nounSingular: string, nounPlural?: string) => {

View file

@ -37,30 +37,30 @@ const isCurrentRoute = (path: string) =>
<slot name="head" />
</Fragment>
<div
class="flex min-h-screen flex-col bg-stone-200 text-stone-800 md:flex-row dark:bg-stone-800 dark:text-stone-200 print:bg-none"
class="flex flex-col bg-stone-200 text-stone-800 md:flex-row dark:bg-stone-800 dark:text-stone-200 print:bg-none"
>
<nav
class="h-card static mb-4 flex flex-col items-center bg-bm-300 pb-10 pt-10 text-center text-stone-900 shadow-xl md:fixed md:inset-y-0 md:left-0 md:mb-0 md:w-60 md:pt-20 dark:bg-green-900 dark:text-stone-100 print:bg-none print:shadow-none"
class="h-card mb-4 flex shrink-0 flex-col items-center border-b-4 border-bm-400 bg-bm-300 pb-10 pt-10 text-center text-stone-900 shadow-xl md:left-0 md:mb-0 md:min-h-screen md:w-72 md:justify-self-stretch md:border-b-0 md:border-r-4 md:pt-20 dark:border-green-950 dark:bg-green-900 dark:text-stone-100 print:bg-none print:shadow-none"
>
<img
loading="eager"
src={logo.src}
alt="A pixelated metal briefcase over a background with a green gradient."
class="u-logo my-4 w-full max-w-[192px] rounded-sm border-2 border-green-950 shadow-md"
class="u-logo my-4 w-full max-w-[192px] rounded-sm border-2 border-green-800 shadow-md dark:border-green-950"
width={192}
/>
<span class="p-name mb-4 mt-2 text-2xl font-semibold">Bad Manners</span>
<ul class="flex flex-col gap-y-2 pr-8 text-left sm:pr-2">
<span class="p-name mb-6 mt-4 text-3xl font-semibold">Bad Manners</span>
<ul class="flex w-[80%] max-w-sm flex-col gap-y-2 px-4 pr-8 text-left sm:pr-2">
<li>
<a class="u-url text-link group" href="https://badmanners.xyz/" data-age-restricted rel="me">
<IconHome width="1.25rem" height="1.25rem" class="inline align-text-top" />
<span class="group-hover:underline group-focus:underline">Main website</span>
<IconHome width="1.25rem" height="1.25rem" class="order-1 inline align-text-top" />
<span class="order-3 group-hover:underline group-focus:underline">Main website</span>
</a>
</li>
<li>
<a class="u-url text-link group" href="/" aria-current={isCurrentRoute("/") ? "page" : undefined}>
<IconBriefcase width="1.25rem" height="1.25rem" class="inline align-text-top" />
<span class="group-hover:underline group-focus:underline">Gallery</span>
<IconBriefcase width="1.25rem" height="1.25rem" class="order-1 inline align-text-top" />
<span class="order-3 group-hover:underline group-focus:underline">Gallery</span>
</a>
</li>
<li>
@ -69,20 +69,20 @@ const isCurrentRoute = (path: string) =>
href="/stories/1"
aria-current={isCurrentRoute("/stories/1") ? "page" : undefined}
>
<IconBook width="1.25rem" height="1.25rem" class="inline align-text-top" />
<span class="group-hover:underline group-focus:underline">Stories</span>
<IconBook width="1.25rem" height="1.25rem" class="order-1 inline align-text-top" />
<span class="order-3 group-hover:underline group-focus:underline">Stories</span>
</a>
</li>
<li>
<a class="u-url text-link group" href="/games" aria-current={isCurrentRoute("/games") ? "page" : undefined}>
<IconGamepad width="1.25rem" height="1.25rem" class="inline align-text-top" />
<span class="group-hover:underline group-focus:underline">Games</span>
<IconGamepad width="1.25rem" height="1.25rem" class="order-1 inline align-text-top" />
<span class="order-3 group-hover:underline group-focus:underline">Games</span>
</a>
</li>
<li>
<a class="u-url text-link group" href="/tags" aria-current={isCurrentRoute("/tags") ? "page" : undefined}>
<IconTags width="1.25rem" height="1.25rem" class="inline align-text-top" />
<span class="group-hover:underline group-focus:underline">Tags</span>
<IconTags width="1.25rem" height="1.25rem" class="order-1 inline align-text-top" />
<span class="order-3 group-hover:underline group-focus:underline">Tags</span>
</a>
</li>
<li>
@ -92,27 +92,35 @@ const isCurrentRoute = (path: string) =>
rel="search"
aria-current={isCurrentRoute("/search") ? "page" : undefined}
>
<IconMagnifyingGlass width="1.25rem" height="1.25rem" class="inline align-text-top" />
<span class="group-hover:underline group-focus:underline">Search</span>
<IconMagnifyingGlass width="1.25rem" height="1.25rem" class="order-1 inline align-text-top" />
<span class="order-3 group-hover:underline group-focus:underline">Search</span>
</a>
</li>
<li>
<a class="u-url text-link group" href="/feed.xml">
<IconSquareRSS width="1.25rem" height="1.25rem" class="inline align-text-top" />
<span class="group-hover:underline group-focus:underline">RSS feed</span>
<IconSquareRSS width="1.25rem" height="1.25rem" class="order-1 inline align-text-top" />
<span class="order-3 group-hover:underline group-focus:underline">RSS feed</span>
</a>
</li>
<li>
<button data-dark-mode style={{ display: "none" }} class="text-link group">
<IconSun width="1.25rem" height="1.25rem" class="hidden align-middle dark:inline" />
<IconMoon width="1.25rem" height="1.25rem" class="inline align-text-top dark:hidden" />
<span class="group-hover:underline group-focus:underline"
>{t("en", "published_content/toggle_dark_mode")}</span
<button
data-dark-mode
style={{ display: "none" }}
class="text-link group"
aria-label={t("en", "published_content/toggle_dark_mode")}
>
<IconSun width="1.25rem" height="1.25rem" class="order-1 hidden align-text-top dark:inline" />
<IconMoon width="1.25rem" height="1.25rem" class="order-1 inline align-text-top dark:hidden" />
<span class="order-3 hidden group-hover:underline group-focus:underline dark:block" aria-hidden="true"
>Light mode</span
>
<span class="order-3 block group-hover:underline group-focus:underline dark:hidden" aria-hidden="true"
>Dark mode</span
>
</button>
</li>
</ul>
<div class="pt-4 text-center text-xs text-black dark:text-white">
<div class="py-6 text-center text-xs text-black dark:text-white">
<span
>&copy; {
currentYear === "2024" ? (
@ -128,10 +136,26 @@ const isCurrentRoute = (path: string) =>
</div>
</nav>
<main
class:list={[className, "ml-0 max-w-6xl px-2 pb-12 pt-4 md:ml-60 md:px-4 print:pb-0"]}
class:list={[className, "ml-0 max-w-6xl px-2 pb-28 pt-4 md:px-4 lg:px-8 print:pb-0"]}
data-pagefind-body={enablePagefind ? "" : undefined}
>
<slot />
</main>
</div>
</BaseLayout>
<style>
nav ul li a,
nav ul li button {
@apply flex w-full items-baseline justify-between;
}
nav ul li a::after,
nav ul li button::after {
@apply order-2 flex-grow self-end bg-bottom;
background: radial-gradient(circle, currentcolor 1px, transparent 1px);
background-size: 1ex 4.5px;
background-repeat: space no-repeat;
content: "";
height: 1ex;
}
</style>

View file

@ -9,7 +9,7 @@ import BaseLayout from "./BaseLayout.astro";
import CopyrightedCharacters from "../components/CopyrightedCharacters.astro";
import Prose from "../components/Prose.astro";
import MastodonComments from "../components/MastodonComments.astro";
import type { CopyrightedCharacters as CopyrightedCharactersType } from "../content/config";
import type { CopyrightedCharacters as CopyrightedCharactersType, Posts } from "../content/config";
import { qualifyLocalURLsInMarkdown } from "../utils/qualify_local_urls_in_markdown";
import {
IconSun,
@ -44,14 +44,7 @@ type Props = {
next?: RelatedContent;
relatedStories?: CollectionEntry<"stories">[];
relatedGames?: CollectionEntry<"games">[];
posts: {
mastodon?: {
link: string;
instance: string;
user: string;
postId: string;
};
};
posts: Posts;
/* Layout attributes */
publishedContentType: "story" | "game";
@ -159,14 +152,14 @@ const thumbnail =
</div>
</div>
<main
class="h-entry mx-auto max-w-5xl rounded-lg bg-stone-50 px-2 pb-10 pt-12 shadow-sm sm:px-6 md:px-20 lg:px-36 dark:bg-stone-900 print:max-w-full print:bg-none print:shadow-none"
class="h-entry mx-auto max-w-6xl rounded-lg bg-stone-50 px-2 pb-10 shadow-sm sm:px-6 md:px-32 lg:px-64 dark:bg-stone-900 print:max-w-full print:bg-none print:shadow-none"
data-pagefind-body={props.isDraft ? undefined : ""}
data-pagefind-meta={`type:${props.publishedContentType}`}
>
{
props.prev || props.next ? (
<div class="print:hidden">
<div id="nav-top" class="my-4 grid grid-cols-2 justify-items-stretch gap-2 text-lg font-light">
<div id="nav-top" class="my-4 grid grid-cols-2 justify-items-stretch gap-2 pt-4 text-lg font-light">
{props.prev ? (
<a
href={props.prev.link}
@ -196,7 +189,9 @@ const thumbnail =
</div>
<hr class="mx-auto mb-5 w-full max-w-2xl border-stone-400 dark:border-stone-600" />
</div>
) : null
) : (
<div class="pt-5 sm:pt-7" aria-hidden="true" />
)
}
<h1
id="section-title"
@ -205,6 +200,7 @@ const thumbnail =
>
{props.title}
</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] w-1/2 rounded-sm bg-stone-800 dark:bg-stone-100" />
<section
id="section-information"
class="p-summary mt-1 space-y-2 px-2 font-serif font-light italic text-stone-600 dark:text-stone-200"

View file

@ -4,6 +4,7 @@ import GalleryLayout from "../layouts/GalleryLayout.astro";
<GalleryLayout pageTitle="404">
<meta slot="head" property="og:description" content="Not found" />
<h1 class="m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">404 &ndash; Not Found</h1>
<h1 class="m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">404 &ndash; Not Found</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
<p class="my-4">The requested link could not be found. Make sure that the URL is correct.</p>
</GalleryLayout>

View file

@ -19,7 +19,8 @@ const games = await Promise.all(
<GalleryLayout pageTitle="Games" class="h-feed">
<meta slot="head" property="og:description" content="Bad Manners || A game that I've gone and done." />
<h1 class="p-name m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">Games</h1>
<h1 class="p-name m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">Games</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
<p class="p-summary my-4">A game that I've gone and done.</p>
<ul class="my-6 flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
{

View file

@ -75,11 +75,12 @@ const latestItems: LatestItemsEntry[] = await Promise.all(
<GalleryLayout pageTitle="Gallery" class="h-feed">
<meta slot="head" property="og:description" content="Bad Manners || Welcome to my gallery!" />
<h1 class="p-name m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">My gallery</h1>
<h1 class="p-name m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">Welcome to my gallery!</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
<div class="p-summary">
<p class="my-4">
Welcome to my gallery! You can expect lots of safe vore/endosoma ahead. Use the navigation menu to navigate
through my content.
Glad to see you here. You can expect lots of safe vore/endosoma ahead. Use the navigation menu to navigate through
my content.
</p>
<ul class="list-disc pl-8">
<li><a class="text-link underline" href="/stories/1">Read my stories!</a></li>

View file

@ -10,6 +10,7 @@ import GalleryLayout from "../layouts/GalleryLayout.astro";
<GalleryLayout pageTitle="Search">
<meta slot="head" property="og:description" content="Bad Manners || Search" />
<h1 class="m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">Search</h1>
<h1 class="m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">Search</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
<SearchComponent id="search" className="pagefind-ui my-4" />
</GalleryLayout>

View file

@ -30,7 +30,8 @@ const totalPages = Math.ceil(page.total / page.size);
<GalleryLayout pageTitle="Stories" class="h-feed">
<meta slot="head" property="og:description" content={`Bad Manners || ${page.total} stories.`} />
<h1 class="p-name m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">Stories</h1>
<h1 class="p-name m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">Stories</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
<div class="p-summary">
<p class="my-4">The bulk of my content!</p>
<p class="text-center font-light text-stone-950 dark:text-white">

View file

@ -26,7 +26,8 @@ const mainChaptersWithSummaries = mainChapters.filter((story) => story.data.summ
property="og:description"
content="The Lost of the Marshes || The story of Quince, Nikili, and Suu."
/>
<h1 class="p-name m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">{series.data.name}</h1>
<h1 class="p-name m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">{series.data.name}</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
<p class="p-summary my-4">
This is the main hub for the story of Quince, Nikili, and Suu, as well as all bonus content.
</p>
@ -43,7 +44,7 @@ const mainChaptersWithSummaries = mainChapters.filter((story) => story.data.summ
>
<summary class="rounded-lg bg-stone-200 px-2 py-1 dark:bg-stone-800">
Click to reveal spoilers up to {
mainChaptersWithSummaries[mainChaptersWithSummaries.length - 1].data.title.match(/Chapter \d+\b/)?.[0]
mainChaptersWithSummaries[mainChaptersWithSummaries.length - 1]!.data.title.match(/Chapter \d+\b/)?.[0]
}
</summary>
<ul class="border-t border-stone-400 px-1 dark:border-stone-500">

View file

@ -71,7 +71,8 @@ if (uncategorizedTagsSet.size > 0) {
<GalleryLayout pageTitle="Tags">
<meta property="og:description" slot="head" content="Bad Manners || Find all content with a specific tag." />
<h1 class="m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">All available tags</h1>
<h1 class="m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">All available tags</h1>
<hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
<p class="my-4">You can find all content with a specific tag by selecting it below from the appropriate category.</p>
<section class="my-2" aria-labelledby="category-series">
<h2 id="category-series" class="p-2 text-xl font-semibold text-stone-800 dark:text-stone-100">Series</h2>

View file

@ -2,6 +2,23 @@
@tailwind components;
@tailwind utilities;
/* Tippy tooltips */
.tippy-box[data-theme~="bm"] {
@apply bg-stone-800 font-sans text-sm text-stone-50 dark:bg-zinc-900 dark:text-zinc-100;
}
.tippy-box[data-theme~="bm"][data-placement^="top"] > .tippy-arrow::before {
@apply border-t-stone-800 dark:border-t-zinc-900;
}
.tippy-box[data-theme~="bm"][data-placement^="bottom"] > .tippy-arrow::before {
@apply border-b-stone-800 dark:border-b-zinc-900;
}
.tippy-box[data-theme~="bm"][data-placement^="left"] > .tippy-arrow::before {
@apply border-l-stone-800 dark:border-l-zinc-900;
}
.tippy-box[data-theme~="bm"][data-placement^="right"] > .tippy-arrow::before {
@apply border-r-stone-800 dark:border-r-zinc-900;
}
@layer components {
.text-link,
.pagefind-ui .pagefind-ui__result-link {

View file

@ -6,7 +6,7 @@ export async function formatCopyrightedCharacters(copyrightedCharacters: Copyrig
Object.values(
Object.keys(copyrightedCharacters).reduce(
(acc, character) => {
const user = copyrightedCharacters[character];
const user = copyrightedCharacters[character]!;
if (user.id in acc) {
acc[user.id][1].push(character);
} else {

View file

@ -18,7 +18,7 @@ export function parsePartialHTMLTag(text: string): ParsedHTMLTag {
const openTag = partialText.match(OPEN_TAG_START_REGEX);
if (openTag) {
const result: ParsedHTMLTag = {
tag: openTag[1],
tag: openTag[1]!,
type: "open",
};
partialText = partialText.slice(openTag[0].length);
@ -30,7 +30,7 @@ export function parsePartialHTMLTag(text: string): ParsedHTMLTag {
if (!result.attributes) {
result.attributes = {};
}
result.attributes[attribute[1]] = attribute[2] ? JSON.parse(attribute[2]) : null;
result.attributes[attribute[1]!] = attribute[2] ? JSON.parse(attribute[2]) : null;
partialText = partialText.slice(attribute[0].length);
}
if (partialText.match(END_OPEN_REGEX)) {
@ -44,7 +44,7 @@ export function parsePartialHTMLTag(text: string): ParsedHTMLTag {
const closeTag = partialText.match(CLOSE_TAG_REGEX);
if (closeTag) {
return {
tag: closeTag[1],
tag: closeTag[1]!,
type: "close",
};
}

View file

@ -1,9 +1,18 @@
import defaultTheme from "tailwindcss/defaultTheme";
import typography from "@tailwindcss/typography";
/** @type {import('tailwindcss').Config} */
export default {
darkMode: ["variant", "@media not print { .dark & }"],
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
content: {
files: [
"./src/components/**/*.astro",
"./src/content/games/**/*.{md,mdx}",
"./src/content/stories/**/*.{md,mdx}",
"./src/layouts/*.astro",
"./src/pages/**/*.{astro,ts}",
],
},
theme: {
extend: {
fontFamily: {