Improve age-restricted hyperlinks and clean up markup
This commit is contained in:
parent
67e17ae27f
commit
4f6b320d31
13 changed files with 117 additions and 63 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { spawn } from "node:child_process";
|
||||
import { join } from "node:path";
|
||||
import { join, normalize as n } from "node:path";
|
||||
import { program, Option } from "commander";
|
||||
|
||||
interface DeployLftpOptions {
|
||||
|
|
@ -17,9 +17,9 @@ async function deployLftp({ host, user, password, targetFolder, sourceFolder, as
|
|||
[
|
||||
"-c",
|
||||
[
|
||||
`open -u ${user},${password} ${host}`,
|
||||
`mirror --reverse --include-glob ${join(assetsFolder, "*")} --delete --only-missing --no-perms --verbose ${sourceFolder} ${targetFolder}`,
|
||||
`mirror --reverse --exclude-glob ${join(assetsFolder, "*")} --delete --no-perms --verbose ${sourceFolder} ${targetFolder}`,
|
||||
`open -u ${user},${password.replaceAll(/([ \t.,:;?!`'"^|*+#&$\(\)\[\]{}<>\\/-])/, "\\$1")} ${host}`,
|
||||
`mirror --reverse --include-glob ${join(assetsFolder, "*")} --delete --only-missing --no-perms --verbose ${n(sourceFolder)} ${n(targetFolder)}`,
|
||||
`mirror --reverse --exclude-glob ${join(assetsFolder, "*")} --delete --no-perms --verbose ${n(sourceFolder)} ${n(targetFolder)}`,
|
||||
`bye`,
|
||||
].join("\n"),
|
||||
],
|
||||
|
|
@ -27,14 +27,10 @@ async function deployLftp({ host, user, password, targetFolder, sourceFolder, as
|
|||
stdio: "inherit",
|
||||
},
|
||||
);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
process.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(`deploy-lftp failed with code ${code}`);
|
||||
}
|
||||
});
|
||||
await new Promise((resolve, reject) => {
|
||||
process.on("close", (code) =>
|
||||
(code === 0) ? resolve(0) : reject(`lftp failed with code ${code}`),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,11 @@ import IconTriangleExclamation from "./icons/IconTriangleExclamation.astro";
|
|||
localStorage.ageVerified = ageVerified;
|
||||
document.body.style.overflow = "auto";
|
||||
document.querySelectorAll("body > :not(#modal-age-restricted)").forEach((el) => el.removeAttribute("inert"));
|
||||
document.body.querySelectorAll<HTMLElementTagNameMap["a"]>("a[href][data-age-restricted]").forEach((el) => {
|
||||
let newHref = new URL(el.href);
|
||||
newHref.searchParams.set("ageVerified", "true");
|
||||
el.href = newHref.href;
|
||||
});
|
||||
modal.style.display = "none";
|
||||
},
|
||||
{ once: true },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
---
|
||||
---
|
||||
|
||||
<script is:inline>function a(){let b=document,c="#modal-age-restricted",d="true",e=b.querySelector("body > "+c);e&&localStorage.ageVerified!==d&&((b.body.style.overflow="hidden"),b.querySelectorAll("body > :not("+c+")").forEach(f=>f.setAttribute("inert",d)),(e.style.display="block"))};document.addEventListener("astro:after-swap",a);a()</script>
|
||||
<script is:inline>function a(){let b=document,c="#modal-age-restricted",d="true",e=b.querySelector("body > "+c),f="ageVerified",g="searchParams",h=localStorage;new URL(b.location)[g].get(f)===d&&(h[f]=d);e&&(h[f]===d?b.querySelectorAll("a[href][data-age-restricted]").forEach(x=>{let y=new URL(x.href);y[g].set(f,d);x.href=y.href}):((b.body.style.overflow="hidden"),b.querySelectorAll("body > :not("+c+")").forEach(x=>x.setAttribute("inert",d)),(e.style.display="block")))};document.addEventListener("astro:after-swap",a);a()</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import SVGIcon from "../SVGIcon.astro";
|
||||
import SVGIcon from "./SVGIcon.astro";
|
||||
|
||||
type Props = {
|
||||
width: string;
|
||||
15
src/components/icons/IconSSHPixel.astro
Normal file
15
src/components/icons/IconSSHPixel.astro
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
import SVGIcon from "./SVGIcon.astro";
|
||||
|
||||
type Props = {
|
||||
width: string;
|
||||
height: string;
|
||||
class?: string;
|
||||
};
|
||||
---
|
||||
|
||||
<SVGIcon {...Astro.props} viewBox="0 0 64 64">
|
||||
<path
|
||||
d="m 19.478516,22.262 v 2.78125 h 8.347656 V 22.262 Z m 8.347656,2.78125 v 2.783203 h 2.783203 V 25.04325 Z m -8.347656,0 h -2.783204 v 5.566406 h 2.783204 z m 0,5.566406 v 2.78125 h 8.347656 v -2.78125 z m 8.347656,2.78125 v 5.566406 h 2.783203 v -5.566406 z m 0,5.566406 h -8.347656 v 2.78125 h 8.347656 z m -8.347656,0 v -2.783203 h -2.783204 v 2.783203 z M 36.173828,22.262 v 2.78125 h 8.347656 V 22.262 Z m 8.347656,2.78125 v 2.783203 h 2.783204 V 25.04325 Z m -8.347656,0 h -2.783203 v 5.566406 h 2.783203 z m 0,5.566406 v 2.78125 h 8.347656 v -2.78125 z m 8.347656,2.78125 v 5.566406 h 2.783204 v -5.566406 z m 0,5.566406 h -8.347656 v 2.78125 h 8.347656 z m -8.347656,0 v -2.783203 h -2.783203 v 2.783203 z M 50.087891,22.262 v 19.476562 h 2.78125 v -8.347656 h 8.347656 v 8.347656 H 64 V 22.262 h -2.783203 v 8.347656 H 52.869141 V 22.262 Z M 0,25.04325 v 2.783203 H 5.5644531 V 25.04325 Z m 5.5644531,2.783203 v 2.783203 h 5.5664059 v -2.783203 z m 5.5664059,2.783203 v 2.78125 h 2.78125 v -2.78125 z m 0,2.78125 H 5.5644531 v 2.783203 H 11.130859 Z M 5.5644531,36.174109 H 0 v 2.783203 h 5.5644531 z"
|
||||
></path>
|
||||
</SVGIcon>
|
||||
|
|
@ -1,4 +1,21 @@
|
|||
import { parse as dateParse } from "date-fns";
|
||||
import { parse } from "date-fns";
|
||||
|
||||
export const TOS_COMMISSION_STATUS: "CLOSED" | "OPEN" | "SEMI_OPEN" | "PRIVATE" = "OPEN";
|
||||
export const TOS_UPDATED_AT: Date = dateParse("2024-07-11", "yyyy-MM-dd", 0);
|
||||
type CommissionStatus = "CLOSED" | "OPEN" | "SEMI_OPEN" | "PRIVATE";
|
||||
|
||||
interface TosFeedItem {
|
||||
status: CommissionStatus;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const parseISODate = (date: string) => parse(date, "yyyy-MM-dd", 0);
|
||||
|
||||
export const TOS_FEED: TosFeedItem[] = (
|
||||
[
|
||||
{ status: "CLOSED", updatedAt: parseISODate("2024-08-25") },
|
||||
{ status: "OPEN", updatedAt: parseISODate("2024-07-11") },
|
||||
] satisfies TosFeedItem[]
|
||||
)
|
||||
.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())
|
||||
.slice(0, 5);
|
||||
|
||||
export const { status: TOS_COMMISSION_STATUS, updatedAt: TOS_UPDATED_AT } = TOS_FEED[0];
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ const title = pageTitle ? `${pageTitle} | Bad Manners` : "Bad Manners";
|
|||
<span class="print:hidden" aria-hidden="true"> | </span>
|
||||
<a
|
||||
href="/licenses.txt"
|
||||
rel="license"
|
||||
class="transition-colors hover:text-white hover:underline focus:text-white focus:underline motion-reduce:transition-none dark:hover:text-bm-300 dark:focus:text-bm-300 print:hidden"
|
||||
>
|
||||
Licenses
|
||||
|
|
|
|||
|
|
@ -5,37 +5,36 @@ const htaccess = String.raw`
|
|||
ErrorDocument 404 /404.html
|
||||
RedirectMatch 301 ^/tos(/(index.html)?)?$ /terms_of_service/
|
||||
RedirectMatch 301 ^/contact(/(index.html)?)?$ /
|
||||
RedirectMatch 301 ^/@/(aryion|ekas?)\b https://aryion.com/g4/user/BadManners
|
||||
RedirectMatch 301 ^/@/(bluesky|bsky)\b https://bsky.app/profile/badmanners.xyz
|
||||
RedirectMatch 301 ^/@/(buymeacoffee|bmac)\b https://www.buymeacoffee.com/BadMannersXYZ
|
||||
RedirectMatch 301 ^/@/(aryion|ekas?(portal)?)\b https://aryion.com/g4/user/BadManners
|
||||
RedirectMatch 301 ^/@/(blue[\ _-]?sky|bsky)\b https://bsky.app/profile/badmanners.xyz
|
||||
RedirectMatch 301 ^/@/(buymeacoffee|buy\ me\ a\ coffee|buy_me_a_coffee|buy-me-a-coffee|bmac)\b https://www.buymeacoffee.com/BadMannersXYZ
|
||||
RedirectMatch 301 ^/@/carrd\b https://badmanners.carrd.co
|
||||
RedirectMatch 301 ^/@/codeberg\b https://codeberg.org/BadManners
|
||||
RedirectMatch 301 ^/@/cohost\b https://cohost.org/BadManners
|
||||
RedirectMatch 301 ^/@/(fur[_-]?affinity|fa)\b https://www.furaffinity.net/user/badmanners
|
||||
RedirectMatch 301 ^/@/gallery\b https://gallery.badmanners.xyz
|
||||
RedirectMatch 301 ^/@/(github|gh)\b https://github.com/BadMannersXYZ
|
||||
RedirectMatch 301 ^/@/gitlab\b https://gitlab.com/Bad_Manners
|
||||
RedirectMatch 301 ^/@/gumroad\b https://badmanners.gumroad.com
|
||||
RedirectMatch 301 ^/@/(inkbunny|ib)\b https://inkbunny.net/BadManners
|
||||
RedirectMatch 301 ^/@/code[\ _-]?berg\b https://codeberg.org/BadManners
|
||||
RedirectMatch 301 ^/@/co[\ _-]?host\b https://cohost.org/BadManners
|
||||
RedirectMatch 301 ^/@/(fur[\ _-]?affinity|fa)\b https://www.furaffinity.net/user/badmanners
|
||||
RedirectMatch 301 ^/@/(gallery|stor(y|ies)|games?)\b https://gallery.badmanners.xyz
|
||||
RedirectMatch 301 ^/@/(git[\ _-]?hub|gh)\b https://github.com/BadMannersXYZ
|
||||
RedirectMatch 301 ^/@/git[\ _-]?lab\b https://gitlab.com/Bad_Manners
|
||||
RedirectMatch 301 ^/@/gum[\ _-]?road\b https://badmanners.gumroad.com
|
||||
RedirectMatch 301 ^/@/(ink[\ _-]?bunny|ib)\b https://inkbunny.net/BadManners
|
||||
RedirectMatch 301 ^/@/itaku\b https://itaku.ee/profile/badmanners
|
||||
RedirectMatch 301 ^/@/itch\b https://bad-manners.itch.io
|
||||
RedirectMatch 301 ^/@/keybase\b https://keybase.io/badmanners
|
||||
RedirectMatch 301 ^/@/ko[_-]?fi\b https://ko-fi.com/badmanners
|
||||
RedirectMatch 301 ^/@/(mastodon|meow\.social|gulp\.cafe)\b https://meow.social/@BadManners
|
||||
RedirectMatch 301 ^/@/neocities\b https://badmanners.neocities.org
|
||||
RedirectMatch 301 ^/@/ko[\ ._-]?fi\b https://ko-fi.com/badmanners
|
||||
RedirectMatch 301 ^/@/(mastodon|meow[\ ._-]?social|gulp[\ ._-]?cafe)\b https://meow.social/@BadManners
|
||||
RedirectMatch 301 ^/@/neo[\ _-]?cities\b https://badmanners.neocities.org
|
||||
RedirectMatch 301 ^/@/picarto\b https://www.picarto.tv/BadManners
|
||||
RedirectMatch 301 ^/@/pillowfort\b https://www.pillowfort.social/BadManners
|
||||
RedirectMatch 301 ^/@/reddit\b https://www.reddit.com/user/BadManners_
|
||||
RedirectMatch 301 ^/@/pillow[\ _-]?fort\b https://www.pillowfort.social/BadManners
|
||||
RedirectMatch 301 ^/@/redd\.?it\b https://www.reddit.com/user/BadManners_
|
||||
RedirectMatch 301 ^/@/signal\b https://signal.me/#eu/ytt_rk0fFmAB2JAW-x2PbUiJyc_H3kYmfL_Pq4QNh5QIDsiFtjdFHaqFRs1D36tB
|
||||
RedirectMatch 301 ^/@/(sofurry|sf)\b https://bad-manners.sofurry.com
|
||||
RedirectMatch 301 ^/@/ssh\b https://badmanners.xyz/ssh.pub
|
||||
RedirectMatch 301 ^/@/steam\b https://steamcommunity.com/id/badmanners_
|
||||
RedirectMatch 301 ^/@/subscribestar\b https://subscribestar.adult/bad-manners
|
||||
RedirectMatch 301 ^/@/(so[\ _-]?furry|sf)\b https://bad-manners.sofurry.com
|
||||
RedirectMatch 301 ^/@/steam([\ _-]?(community|powered))?\b https://steamcommunity.com/id/badmanners_
|
||||
RedirectMatch 301 ^/@/subscribe[\ _-]?star\b https://subscribestar.adult/bad-manners
|
||||
RedirectMatch 301 ^/@/(telegram|t\.me)\b https://t.me/bad_manners
|
||||
RedirectMatch 301 ^/@/twitch\b https://www.twitch.tv/bad__manners
|
||||
RedirectMatch 301 ^/@/weasyl\b https://www.weasyl.com/~badmanners
|
||||
RedirectMatch 301 ^/@/(x|twitter)\b https://x.com/BadManners__
|
||||
RedirectMatch 301 ^/@/(youtu\.?be|yt)\b https://www.youtube.com/@BadMannersXYZ
|
||||
RedirectMatch 301 ^/@/(you[\ _-]?tube|youtu\.be|yt)\b https://www.youtube.com/@BadMannersXYZ
|
||||
`.trim();
|
||||
|
||||
export const getStaticPaths: GetStaticPaths = async () => {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import ImageSamStickerJuicebox from "../assets/images/sam_sticker_juicebox.webp"
|
|||
<a
|
||||
class="h-card u-url text-link transition-colors motion-reduce:transition-none"
|
||||
href="https://olivecow.carrd.co/"
|
||||
rel="nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
<span class="p-name underline">OliveCow</span>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,22 @@
|
|||
import rss from "@astrojs/rss";
|
||||
import type { APIRoute } from "astro";
|
||||
import { set as dateSet, subMinutes } from "date-fns";
|
||||
import { TOS_COMMISSION_STATUS, TOS_UPDATED_AT } from "../data/tos";
|
||||
import { TOS_FEED } from "../data/tos";
|
||||
|
||||
export const GET: APIRoute = async ({ site }) => {
|
||||
export const GET: APIRoute = ({ site }) => {
|
||||
return rss({
|
||||
title: "Bad Manners",
|
||||
description: "Bad Manners status updates",
|
||||
site: site!,
|
||||
items: [
|
||||
{
|
||||
title: {
|
||||
CLOSED: "Story commissions are closed.",
|
||||
OPEN: "Story commissions are open!",
|
||||
SEMI_OPEN: "Story commissions are semi-open, and I may accept them less frequently.",
|
||||
PRIVATE: "Story commissions are private; they are only open to select commissioners.",
|
||||
}[TOS_COMMISSION_STATUS],
|
||||
link: "https://badmanners.xyz/terms_of_service",
|
||||
pubDate: subMinutes(
|
||||
dateSet(TOS_UPDATED_AT, { hours: 12, minutes: 0, seconds: 0 }),
|
||||
TOS_UPDATED_AT.getTimezoneOffset(),
|
||||
),
|
||||
},
|
||||
],
|
||||
items: TOS_FEED.map(({ status, updatedAt }) => ({
|
||||
title: {
|
||||
CLOSED: "Story commissions are closed.",
|
||||
OPEN: "Story commissions are open!",
|
||||
SEMI_OPEN: "Story commissions are semi-open, and I may accept them less frequently.",
|
||||
PRIVATE: "Story commissions are private; they are only open to select commissioners.",
|
||||
}[status],
|
||||
link: "https://badmanners.xyz/terms_of_service",
|
||||
pubDate: subMinutes(dateSet(updatedAt, { hours: 12, minutes: 0, seconds: 0 }), updatedAt.getTimezoneOffset()),
|
||||
})),
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
import IconEnvelope from "../components/icons/IconEnvelope.astro";
|
||||
import IconBriefcase from "../components/icons/IconBriefcase.astro";
|
||||
import IconBluesky from "../components/icons/brands/IconBluesky.astro";
|
||||
import IconCodeberg from "../components/icons/brands/IconCodeberg.astro";
|
||||
import IconCohost from "../components/icons/brands/IconCohost.astro";
|
||||
|
|
@ -21,6 +22,7 @@ import IconPicarto from "../components/icons/brands/IconPicarto.astro";
|
|||
import IconReddit from "../components/icons/brands/IconReddit.astro";
|
||||
import IconSignal from "../components/icons/brands/IconSignal.astro";
|
||||
import IconSoFurry from "../components/icons/brands/IconSoFurry.astro";
|
||||
import IconSSH from "../components/icons/IconSSH.astro";
|
||||
import IconSteam from "../components/icons/brands/IconSteam.astro";
|
||||
import IconSubscribeStar from "../components/icons/brands/IconSubscribeStar.astro";
|
||||
import IconTelegram from "../components/icons/brands/IconTelegram.astro";
|
||||
|
|
@ -28,7 +30,6 @@ import IconTwitch from "../components/icons/brands/IconTwitch.astro";
|
|||
import IconWeasyl from "../components/icons/brands/IconWeasyl.astro";
|
||||
import IconX from "../components/icons/brands/IconX.astro";
|
||||
import IconYouTube from "../components/icons/brands/IconYouTube.astro";
|
||||
import IconSSH from "../components/icons/brands/IconSSH.astro";
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
|
|
@ -39,7 +40,7 @@ import IconSSH from "../components/icons/brands/IconSSH.astro";
|
|||
/>
|
||||
<article class="h-card" aria-label="Homepage of Bad Manners">
|
||||
<h1 id="title-home" class="pb-4 text-3xl tracking-tight sm:text-5xl">
|
||||
Hi, I'm <span class="p-name">Bad Manners</span>!
|
||||
Hi, I'm <span class="p-name font-medium">Bad Manners</span>!
|
||||
</h1>
|
||||
<section>
|
||||
<img
|
||||
|
|
@ -48,7 +49,7 @@ import IconSSH from "../components/icons/brands/IconSSH.astro";
|
|||
alt="Logo for Bad Manners"
|
||||
class="u-logo mx-auto my-4 h-screen max-h-48 rounded-full transition-transform hover:scale-110 motion-reduce:transition-none motion-reduce:hover:scale-100 sm:max-h-72"
|
||||
/>
|
||||
<p class="p-note mt-6 sm:px-5 md:px-6">I'm a safe vore enthusiast, and a furry who occasionally writes stuff.</p>
|
||||
<p class="p-note mt-6 sm:px-5 md:px-6">I'm a safe vore enthusiast, a furry programmer, and occasionally a writer.</p>
|
||||
{
|
||||
Astro.site ? (
|
||||
<a href={Astro.site} class="u-url sr-only" aria-label="Permalink">
|
||||
|
|
@ -78,6 +79,21 @@ import IconSSH from "../components/icons/brands/IconSSH.astro";
|
|||
<p class="sr-only">E-mail address</p>
|
||||
</a>
|
||||
</li>
|
||||
<li id="gallery">
|
||||
<a
|
||||
class="u-url text-link group block w-full transition-colors motion-reduce:transition-none"
|
||||
href="https://gallery.badmanners.xyz"
|
||||
rel="me"
|
||||
aria-label="Main gallery"
|
||||
data-age-restricted
|
||||
>
|
||||
<IconBriefcase
|
||||
height="1.75rem"
|
||||
width="1.75rem"
|
||||
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li id="bluesky">
|
||||
<a
|
||||
class="u-url text-link group block w-full transition-colors motion-reduce:transition-none"
|
||||
|
|
@ -394,7 +410,6 @@ import IconSSH from "../components/icons/brands/IconSSH.astro";
|
|||
width="1.75rem"
|
||||
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
|
||||
/>
|
||||
<p class="sr-only">SSH public key</p>
|
||||
</a>
|
||||
</li>
|
||||
<li id="steam">
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import ImageSamRefsheet from "../assets/images/sam_refsheet.webp";
|
|||
<a
|
||||
class="group mx-auto mb-1 block w-max max-w-full pb-0 sm:mb-3"
|
||||
href="https://booru.badmanners.xyz/index.php?q=post/view/1"
|
||||
data-age-restricted
|
||||
target="_blank"
|
||||
>
|
||||
<Image
|
||||
|
|
@ -40,6 +41,7 @@ import ImageSamRefsheet from "../assets/images/sam_refsheet.webp";
|
|||
<a
|
||||
class="h-card u-url text-link transition-colors motion-reduce:transition-none"
|
||||
href="https://linktr.ee/Rimmi1357"
|
||||
rel="nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
<span class="p-name underline">Rimmi</span>
|
||||
|
|
@ -77,6 +79,7 @@ import ImageSamRefsheet from "../assets/images/sam_refsheet.webp";
|
|||
<a
|
||||
class="group mx-auto mb-1 block w-max max-w-full pb-0 sm:mb-3"
|
||||
href="https://booru.badmanners.xyz/index.php?q=post/view/2"
|
||||
data-age-restricted
|
||||
target="_blank"
|
||||
>
|
||||
<Image
|
||||
|
|
@ -92,6 +95,7 @@ import ImageSamRefsheet from "../assets/images/sam_refsheet.webp";
|
|||
<a
|
||||
class="h-card u-url text-link transition-colors motion-reduce:transition-none"
|
||||
href="https://olivecow.carrd.co/"
|
||||
rel="nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
<span class="p-name underline">OliveCow</span>
|
||||
|
|
|
|||
|
|
@ -22,10 +22,13 @@ import { SUBSCRIBESTAR_ENABLED } from "../data/subscribestar";
|
|||
I've been a lurker in the furry vore community for a long time before I decided to start writing
|
||||
<a
|
||||
class="text-link transition-colors motion-reduce:transition-none"
|
||||
href="https://gallery.badmanners.xyz/stories/1"><span class="underline">safe vore stories</span></a
|
||||
href="https://gallery.badmanners.xyz/stories/1"
|
||||
data-age-restricted><span class="underline">safe vore stories</span></a
|
||||
>. Since there's a lot in furry endosoma that I enjoy, my stories tend to
|
||||
<a class="text-link transition-colors motion-reduce:transition-none" href="https://gallery.badmanners.xyz/tags"
|
||||
><span class="underline">have all sorts of themes and scenarios</span></a
|
||||
<a
|
||||
class="text-link transition-colors motion-reduce:transition-none"
|
||||
href="https://gallery.badmanners.xyz/tags"
|
||||
data-age-restricted><span class="underline">have all sorts of themes and scenarios</span></a
|
||||
>, including exotic ones. My content is all tagged with the appropriate content warnings, so if you enjoy safe
|
||||
vore, chances are that you'll find something in my gallery that is right up your alley.
|
||||
</p>
|
||||
|
|
@ -33,7 +36,8 @@ import { SUBSCRIBESTAR_ENABLED } from "../data/subscribestar";
|
|||
I've also made a game called
|
||||
<a
|
||||
class="text-link transition-colors motion-reduce:transition-none"
|
||||
href="https://gallery.badmanners.xyz/games/crossing-over"><span class="underline">"Crossing Over"</span></a
|
||||
href="https://gallery.badmanners.xyz/games/crossing-over"
|
||||
data-age-restricted><span class="underline">"Crossing Over"</span></a
|
||||
>, as part of Strawberry Jam 8 (a game jam hosted by eevee on Feb. 2024). It's been my biggest project so far,
|
||||
and I'm very proud of it! Check it out if you have an hour to spare and the subject matters interest you.
|
||||
</p>
|
||||
|
|
@ -46,6 +50,7 @@ import { SUBSCRIBESTAR_ENABLED } from "../data/subscribestar";
|
|||
<a
|
||||
class="u-url text-link mx-1 transition-colors motion-reduce:transition-none"
|
||||
href="https://gallery.badmanners.xyz"
|
||||
data-age-restricted
|
||||
>
|
||||
<IconBriefcase height="1.75rem" width="1.75rem" class="mr-1 inline" />
|
||||
<span class="underline">gallery.badmanners.xyz</span>
|
||||
|
|
@ -210,6 +215,7 @@ import { SUBSCRIBESTAR_ENABLED } from "../data/subscribestar";
|
|||
<a
|
||||
href="https://desiran.itch.io/wrangler"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
class="text-link transition-colors motion-reduce:transition-none"
|
||||
>
|
||||
<span class="underline">Wrangler</span>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue