Add syndication links and start blog collection
This commit is contained in:
parent
09934a9f8e
commit
9ff1986adc
80 changed files with 415 additions and 33 deletions
.vscode
src
components
content
blog/drafts
config.tsstories
accommodation.mdaddictive-additions.mdannivoresary.mdbetter-in-bully-batter.mdbig-haul.mdbirdroom.mdbladder-filler.mdbottom-of-the-food-chain.mdbutting-into-their-plans.mddelicacy-s-dare.mdeggs-for-months.mdengaging-contacts.mdflavorful-favor.mdfor-the-night.mdgentle-and-cruel.mdhate-to-sea-it.mdhungry-for-love.mdhyper-hunger.mdinsistence-and-assistance.mdlactation-action.mdlatest-catch.mdnever-too-late.mdnoble-fire.mdoverzealous-zenko.mdpart-of-the-show.mdpet-sit-saturday.mdplaying-it-safe.mdreaching-for-the-full-moon.mdrose-s-binge.mdruffling-some-feathers.mdspontaneous-sleepover.mdtaken-in.mdtasting-high-consequences.mdteam-building.mdteam-effort.mdthe-last-livestream.md
the-lost-of-the-marshes
bonus-1-quince-s-fantasy.mdchapter-1.mdchapter-10.mdchapter-11.mdchapter-2.mdchapter-3.mdchapter-4.mdchapter-5.mdchapter-6.mdchapter-7.mdchapter-8.mdchapter-9.md
tiny-accident.mdtomo-moku.mdtrouble-sleeping.mdwarped-friendship.mdwithin-limits.mdwoofer-exploration.mdyou-re-home.mdtag-categories
users
data
i18n
layouts
pages
utils
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -32,6 +32,5 @@
|
|||
},
|
||||
"prettier.requireConfig": true,
|
||||
"prettier.configPath": ".prettierrc.mjs",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
|
|
|
@ -57,8 +57,8 @@ import { IconTriangleExclamation } from "./icons";
|
|||
<script>
|
||||
const ageRestrictedModalSetup = () => {
|
||||
const modal = document.querySelector<HTMLElementTagNameMap["div"]>("div#modal-age-restricted");
|
||||
// Not an age-restricted page
|
||||
if (!modal) {
|
||||
// Not an age-restricted page
|
||||
return;
|
||||
}
|
||||
if (modal !== document.querySelector("body>div#modal-age-restricted")) {
|
||||
|
|
100
src/components/ExternalPosts.astro
Normal file
100
src/components/ExternalPosts.astro
Normal file
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
import type { Posts } from "../content/config";
|
||||
import { t, type Lang } from "../i18n";
|
||||
import { IconEkasPortal, IconFurAffinity, IconInkbunny, IconSoFurry, IconWeasyl } from "./icons/brands";
|
||||
|
||||
type Props = {
|
||||
lang: Lang;
|
||||
posts?: Posts;
|
||||
};
|
||||
|
||||
const { lang, posts } = Astro.props;
|
||||
const { eka, furaffinity, inkbunny, sofurry, weasyl } = posts ?? {};
|
||||
const isVisible = eka || furaffinity || inkbunny || sofurry || weasyl;
|
||||
---
|
||||
|
||||
{
|
||||
isVisible ? (
|
||||
<section id="external-posts-section" class="my-5 px-2 font-serif" aria-describedby="title-external-posts">
|
||||
<>
|
||||
<h2 id="title-external-posts" class="py-2 font-serif text-xl font-semibold text-stone-800 dark:text-stone-100">
|
||||
{t(lang, "published_content/syndication_see_also_on")}
|
||||
</h2>
|
||||
<ul id="external-posts" class="flex flex-wrap justify-around">
|
||||
{eka ? (
|
||||
<li class="min-w-12 grow">
|
||||
<a
|
||||
class="u-syndication text-link w-full"
|
||||
href={eka.link}
|
||||
target="_blank"
|
||||
aria-label={t(lang, "published_content/syndication_eka")}
|
||||
>
|
||||
<IconEkasPortal class="mx-auto" width="2rem" height="2rem" />
|
||||
</a>
|
||||
</li>
|
||||
) : null}
|
||||
{furaffinity ? (
|
||||
<li class="min-w-12 grow">
|
||||
<a
|
||||
class="u-syndication text-link w-full"
|
||||
href={furaffinity.link}
|
||||
target="_blank"
|
||||
aria-label={t(lang, "published_content/syndication_furaffinity")}
|
||||
>
|
||||
<IconFurAffinity class="mx-auto" width="2rem" height="2rem" />
|
||||
</a>
|
||||
</li>
|
||||
) : null}
|
||||
{inkbunny ? (
|
||||
<li class="min-w-12 grow">
|
||||
<a
|
||||
class="u-syndication text-link w-full"
|
||||
href={inkbunny.link}
|
||||
target="_blank"
|
||||
aria-label={t(lang, "published_content/syndication_inkbunny")}
|
||||
>
|
||||
<IconInkbunny class="mx-auto" width="2rem" height="2rem" />
|
||||
</a>
|
||||
</li>
|
||||
) : null}
|
||||
{sofurry ? (
|
||||
<li class="min-w-12 grow">
|
||||
<a
|
||||
class="u-syndication text-link w-full"
|
||||
href={sofurry.link}
|
||||
target="_blank"
|
||||
aria-label={t(lang, "published_content/syndication_sofurry")}
|
||||
>
|
||||
<IconSoFurry class="mx-auto" width="2rem" height="2rem" />
|
||||
</a>
|
||||
</li>
|
||||
) : null}
|
||||
{weasyl ? (
|
||||
<li class="min-w-12 grow">
|
||||
<a
|
||||
class="u-syndication text-link w-full"
|
||||
href={weasyl.link}
|
||||
target="_blank"
|
||||
aria-label={t(lang, "published_content/syndication_weasyl")}
|
||||
>
|
||||
<IconWeasyl class="mx-auto" width="2rem" height="2rem" />
|
||||
</a>
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
</>
|
||||
</section>
|
||||
) : null
|
||||
}
|
||||
|
||||
<script>
|
||||
import tippy from "tippy.js";
|
||||
import "tippy.js/dist/tippy.css";
|
||||
|
||||
const clipboardItems = document.querySelectorAll<HTMLElement>("ul#external-posts a[aria-label]");
|
||||
|
||||
tippy(clipboardItems, {
|
||||
content: (el) => (el as HTMLElement).getAttribute("aria-label")!,
|
||||
theme: "bm",
|
||||
});
|
||||
</script>
|
|
@ -8,9 +8,10 @@ type Props = {
|
|||
instance: string;
|
||||
user: string;
|
||||
postId: string;
|
||||
blacklistedComments?: string[];
|
||||
};
|
||||
|
||||
const { link, instance, user, postId } = Astro.props;
|
||||
const { link, instance, user, postId, blacklistedComments } = Astro.props;
|
||||
---
|
||||
|
||||
<section
|
||||
|
@ -21,6 +22,7 @@ const { link, instance, user, postId } = Astro.props;
|
|||
data-instance={instance}
|
||||
data-user={user}
|
||||
data-post-id={postId}
|
||||
data-blacklisted={(blacklistedComments ?? []).join(",")}
|
||||
>
|
||||
<h2 id="title-comments-section" class="py-2 font-serif text-xl font-semibold text-stone-800 dark:text-stone-100">
|
||||
Comments
|
||||
|
@ -45,7 +47,7 @@ const { link, instance, user, postId } = Astro.props;
|
|||
class="group mx-auto w-64 rounded-lg bg-bm-300 px-4 py-1 text-stone-800 disabled:bg-bm-400 dark:bg-green-800 dark:text-stone-100 dark:disabled:bg-green-900"
|
||||
id="load-comments-button"
|
||||
>
|
||||
<span class="block underline group-disabled:hidden">Click to load comments</span>
|
||||
<span class="block hover:underline group-focus:underline group-disabled:hidden">Click to load comments</span>
|
||||
<span class="hidden group-disabled:block">
|
||||
<svg
|
||||
style={{ width: "1.25rem", height: "1.25rem", display: "inline" }}
|
||||
|
@ -144,6 +146,7 @@ const { link, instance, user, postId } = Astro.props;
|
|||
reblogs_count: number;
|
||||
created_at: string;
|
||||
edited_at: string | null;
|
||||
language: string | null;
|
||||
account: {
|
||||
username: string;
|
||||
acct: string;
|
||||
|
@ -162,7 +165,7 @@ const { link, instance, user, postId } = Astro.props;
|
|||
descendants: Status[];
|
||||
}
|
||||
|
||||
async function renderComments(section: Element, post: MastodonPost) {
|
||||
async function renderComments(section: Element, post: MastodonPost, blacklistedComments: Set<string>) {
|
||||
const commentsDescription = section.querySelector<HTMLElementTagNameMap["p"]>("p#comments-description")!;
|
||||
const loadCommentsButton = section.querySelector<HTMLElementTagNameMap["button"]>("button#load-comments-button")!;
|
||||
try {
|
||||
|
@ -198,6 +201,13 @@ const { link, instance, user, postId } = Astro.props;
|
|||
)!;
|
||||
|
||||
data.descendants.forEach((comment) => {
|
||||
if (blacklistedComments.has(comment.id)) {
|
||||
return;
|
||||
}
|
||||
if (blacklistedComments.has(comment.in_reply_to_id)) {
|
||||
blacklistedComments.add(comment.id);
|
||||
return;
|
||||
}
|
||||
const commentBox = commentTemplate.content.cloneNode(true) as DocumentFragment;
|
||||
commentBox.firstElementChild!.id = `comment-${comment.id}`;
|
||||
|
||||
|
@ -303,6 +313,8 @@ const { link, instance, user, postId } = Astro.props;
|
|||
if (!post.link || !post.instance || !post.user || !post.postId) {
|
||||
return;
|
||||
}
|
||||
const blacklisted = commentSection.dataset.blacklisted;
|
||||
const blacklistedComments = new Set(blacklisted ? blacklisted.split(",") : undefined);
|
||||
const loadCommentsButton =
|
||||
commentSection.querySelector<HTMLElementTagNameMap["button"]>("button#load-comments-button")!;
|
||||
loadCommentsButton.addEventListener(
|
||||
|
@ -310,7 +322,7 @@ const { link, instance, user, postId } = Astro.props;
|
|||
(e) => {
|
||||
e.preventDefault();
|
||||
loadCommentsButton.disabled = true;
|
||||
renderComments(commentSection, post as MastodonPost);
|
||||
renderComments(commentSection, post as MastodonPost, blacklistedComments);
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
|
|
15
src/components/icons/brands/IconEkasPortal.astro
Normal file
15
src/components/icons/brands/IconEkasPortal.astro
Normal file
File diff suppressed because one or more lines are too long
15
src/components/icons/brands/IconFurAffinity.astro
Normal file
15
src/components/icons/brands/IconFurAffinity.astro
Normal file
File diff suppressed because one or more lines are too long
15
src/components/icons/brands/IconInkbunny.astro
Normal file
15
src/components/icons/brands/IconInkbunny.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 72 72">
|
||||
<path
|
||||
d="M58.914 44.015c-.247.468-1.187 1.528-1.95 1.98-1.493.873-1.984 1.014-1.65.48.299-.483-1.403-.035-2.613.696-.55.326-1.211.898-1.326.783-.388-.388-1.69 3.786-1.535 4.82.174 2.417-1.846 3.545-3.733 5.455-1.885 1.908-3.682 3.793-3.816 3.793-.134 0-.756-.771-2.183-2.496-3.132-3.781-4.04-5.785-4.088-8.04.07-.472 1.116-.812 1.943-1.045 1.046-.29 2.79-1.198 2.79-1.198s2.917-1.63 3.026-1.694c.684-.35 1.374-.929 1.755-1.268 1.093-.943 1.736-2.4 1.929-3.16.134-.536-.288-1.356-.756-2.11l-.66-1.14.813-3.384c.467-1.795.455-4.315 1.54-5.147 2.835-.935 5.735-5.197 8.36-9.084 4.032-5.97 5.191-10.89 3.14-13.33-1.568-1.86-3.662-1.506-10.12 1.713-2.213 1.104-5.978 3.183-8.363 4.618-2.385 1.438-4.386 2.57-4.437 2.519-.05-.055.13-1.459.401-3.121.755-4.594.97-9.542.503-11.495C37.381 1.068 36.273-.016 34.83 0c-.864.008-1.846.413-2.893 1.234-4.306 3.384-9.427 10.025-11.403 16.29-1.62 5.134-3.793 16.975-3.538 19.958.52 6.127.924 5.226-.33 7.368C13.137 50.87 11 59.585 11 67.936c0 3.744-.43 4.064.125 4.064h2.986c.444-.083.287-.795.444-5.393.196-5.765.79-9.322 2.342-14.018.849-2.57 3.149-7.487 4.092-8.737.16-.216.44-.381.46-.577.035-.32-.134-.74-.516-1.534-.57-1.182-.837-2.047-.837-5.317.173-3.352.232-3.984.845-5.364.126-.291.524-1.019.68-1.56.33-1.125.311-2.488.546-3.863 1.584-9.31 3.232-14.91 8.526-20.452 3.168-2.848 4.552-3.734 4.54 1.023.334 4-1.334 12.948-3.056 17.381-.519 1.337-1.179 2.638-1.123 2.693.255.326 3.547-.484 3.91-1.597.133-.405.174-.398.318-.376.143.021 1.478 1.026 1.921 1.131.495.11 1.828-.515 1.876-.715.046-.2-2.593-1.83-2.774-1.997-.034-.388-.099-.453-.015-.825.084-.372.14-.615.899-1.105.758-.49 16.982-10.218 19.577-10.27.94-.039 1.35 1.426 1.368 1.935.017.509.04 2.72-.999 4.24-1.038 1.521-8.414 11.11-9.282 11.873-.867.763-2.678.75-3.319.386s-3.705-1.568-3.437-1.069c.271.503 1.255 1.324 1.79 1.933.369.44.99 1.265 1.38 1.835l.585.998-1.65 7.365.758 1.113c.597 1.014.605 1.143.126 2.142-.236.479-1.026 1.245-1.706 1.93-.31.286-4.578 3.006-6.96 3.776-1.781.515-1.615.295-3.12-.008-1.506-.302-4.52-2.453-5.124-1.858-.604.596.877 1.813 1.328 1.988.45.174.61.564 1.328.859.501.216 1.186 1.002 1.221 1.486.031.633.055.525.094 1.126.095 3.914.833 5.966 3.942 12.862 1.207 2.677 2.29 5.247 2.41 5.715.14.562.11.845.542.845h1.963c.597 0-.059-1.753-2.244-6.626-3.474-7.758-4.613-11.628-2.877-9.005.62 1.03 2.13 3.055 3.352 4.493 4.453 5.247 5.384 7.306 4.39 9.688-.42 1.002-.594 1.45-.26 1.45h2.09c.448 0 .579-.137.898-.896.573-1.378 1.536-2.204.95-3.842l-.243-1.14 2.936-4.048c1.064-1.399 2.203-3.179 2.738-3.761.538-.582.664-.797.664-.797.495.24 2.253-.09 2.522-.351.268-.261-.632-.143-.749-.538-.102-.169.707-.677 1.422-.965 1.418-.57 2.842-2.264 2.932-2.975.245-.297.267.551.277.93-.024.628-1.583 2.249-2.043 3.22-.46.973-.692 1.46-.543 2.44.149.98 1.215 1.857 2.648 1.787 1.432-.07 2.275-.936 2.295-2.316.02-1.565-1.778-6.887-1.667-6.864.11.028.382-7.094.22-7.793-.162-.699-.437-.795-.437-.795zm-33.575-7.213c.008.425 1.333.585 1.44-.075.157-.99 1.24-1.77 2.004-1.707.764.061 1.194.103 1.556.815.363.713.14 1.378.24 1.654.102.276 1.16.317 1.227-.133.066-.451.319-2.732-.927-3.389-1.247-.657-2.26-.776-3.545-.294-1.286.482-2.019 1.863-1.995 3.13zm15.64 1.859c.066-.21.446-.797.856-.574.41.222.252.614.245.81-.007.195.68.652.798.415.118-.237.186-.63.191-.795.006-.166.081-.753-.226-1.053-.307-.3-.894-.548-1.583-.33-.69.217-1.111.871-1.195 1.15-.084.277.846.587.913.377zm-6.251-1.067s.998 1.791 1.358 2.158c.36.367 1.502.72 2.08.456.578-.263 1.245-1.528 1.276-1.775a136.192 136.192 0 0 1-4.714-.84zm-.063 5.955c-.837.182-2.516.256-3.887-.012-1.371-.271-2.343.357-2.013.676.668.637 1.955.795 2.753.906 1.268.173 2.766-.017 3.207-.085.44-.068 1.364-.557 1.482-.47.06.044.616.507 1.245.822.596.298 1.47.464 1.727.503.256.039.982-.631.795-.747-.188-.115-.727-.27-1.018-.367a4.407 4.407 0 0 1-1.13-.542c-.533-.351-1.057-.865-1.2-1.23-.144-.366-.389.024-.7.157-.412.177-.424.205-1.261.39zm15.387 14.486c-1.143 1.549-1.374 1.888-2.364 3.201-1.446 1.91-2.78 3.526-2.955 3.585-.177.058-.511-.19-.735-.55-.374-.602-.146-.956 2.542-3.946 1.154-1.29 1.563-1.734 2.73-3.012.252-.272.458-.51.59-.503.132.006.631.368.732.44.1.072-.145.329-.54.785zM20.637 68.697c-.146 2.28-.126 3.301.118 3.301h1.764c.181 0 .123-.427.13-.887.031-3.03.812-8.371 1.31-12.02.116-.793-.597-1.307-1.142-1.115-.543.192-1.968 7.365-2.18 10.721z"
|
||||
></path>
|
||||
</SVGIcon>
|
15
src/components/icons/brands/IconSoFurry.astro
Normal file
15
src/components/icons/brands/IconSoFurry.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="M16.998 56.139c-3.483-.313-6.077-1.151-8.817-2.85-1.2-.745-1.99-1.373-3.22-2.565-1.27-1.23-2.101-2.23-3.042-3.663C1.323 46.154.004 43.696 0 43.484c-.003-.127.642-.091 1.265.07.316.082.59.134.609.116.019-.019-.066-.356-.187-.75-.703-2.275-.741-5.302-.1-7.857.679-2.702 2.023-5.117 3.99-7.169l1-1.043.178.567c.098.311.18.697.184.856.004.159.034.29.067.29s.41-.214.839-.474c3.491-2.12 7.817-2.179 11.225-.154.818.486 2.199 1.744 2.774 2.528.545.742 1.16 2.037 1.461 3.08.431 1.489.534 3.07.317 4.867l-.052.428-.707-.185c-1.395-.363-3.021-.203-4.173.411-.818.437-1.795 1.463-2.194 2.306-.32.674-.34.79-.34 1.876 0 1.085.021 1.203.337 1.87.415.876 1.157 1.613 2.083 2.069.722.356 1.837.636 2.527.636 1.224 0 3.052-.707 4.125-1.596 1.722-1.427 2.622-3.392 2.738-5.979.126-2.809-.505-5.298-2.39-9.42-1.822-3.984-2.493-6.404-2.599-9.38-.047-1.327-.022-1.926.118-2.764.42-2.509 1.414-4.424 3.18-6.127 2.175-2.097 5.092-3.31 8.256-3.437 1.262-.05 2.372.037 3.056.241.138.041.18-.07.23-.611.094-1.003.13-1.059.533-.851 1.488.766 3.272 2.398 4.234 3.875 1.201 1.842 1.712 3.483 1.802 5.79.065 1.662-.025 2.381-.92 7.387-.766 4.282-.875 5.151-.878 7.034-.003 1.482.024 1.76.228 2.31.198.533.775 1.323.965 1.321.032 0 .246-.367.476-.816.76-1.484 2.01-3.227 3.211-4.478 1.323-1.376 2.578-2.318 4.01-3.01l1.006-.486-.208-.473c-.146-.332-.223-.795-.258-1.56l-.05-1.086.41.07c1.318.222 2.772.758 3.846 1.42.282.173.524.315.538.315.013 0 .033-.344.045-.764.01-.42.06-.873.11-1.006l.09-.243.646.432c.847.565 2.001 1.717 2.788 2.78.347.47.661.865.698.88.038.014.2-.227.361-.535.161-.308.43-.722.597-.92l.305-.361.321.702c1.306 2.858 1.648 8.456.85 13.93-.844 5.791-2.563 9.862-5.357 12.686-2.172 2.195-4.194 3.067-7.104 3.063-1.668-.002-2.857-.2-4.497-.747-1.439-.48-2.255-.873-3.407-1.639-.922-.612-2.01-1.65-1.907-1.818.087-.14.98-.44 1.32-.443.53-.003.57-.121.27-.797-1.435-3.23-1.511-7.903-.197-12.062.147-.466.228-.882.18-.925-.048-.042-.29-.155-.537-.25-1.532-.593-2.635-1.942-3.154-3.858-.153-.565-.185-1.116-.181-3.158.004-2.199.044-2.772.362-5.158.468-3.513.507-5.76.121-6.88-.694-2.01-2.422-3.286-4.155-3.069-1.851.232-3.602 2.117-3.965 4.27-.295 1.75.205 3.449 2.138 7.258 1.965 3.873 2.696 5.787 3.218 8.42.623 3.15.589 6.597-.091 9.26-1.628 6.378-6.329 10.363-13.474 11.424-1.344.2-4.718.285-6.158.156zm38.56-5.629c1.611-.75 3.426-3.418 4.488-6.598 1.291-3.866 1.285-8.376-.015-11.01-.432-.875-1.105-1.543-1.66-1.647-.81-.152-2.248.65-3.448 1.922-1.708 1.81-2.954 4.326-3.559 7.182-.318 1.505-.4 4.178-.17 5.572.39 2.366 1.245 3.993 2.402 4.57.69.343 1.238.346 1.961.01zm-42.375-7.5c.099-1.947.728-3.439 2.058-4.878 1.197-1.295 2.751-2.147 4.532-2.484.538-.101.962-.234.962-.3 0-.066-.094-.485-.208-.931-.487-1.904-1.661-3.363-3.396-4.22-1.314-.648-2.2-.823-3.87-.764-1.518.054-2.535.329-3.684.995-.964.56-2.384 1.997-2.976 3.014-.489.838-1.332 3.164-1.196 3.3.106.105 1.495-.15 1.873-.345.175-.091.342-.142.37-.114.028.028.155.692.282 1.475.127.783.253 1.446.281 1.474.028.027.642-.086 1.366-.252.724-.167 1.39-.305 1.479-.307.138-.004.156.142.119.988-.076 1.746.384 3.107 1.37 4.056.244.233.474.425.512.425.038 0 .095-.51.126-1.132z"
|
||||
></path>
|
||||
</SVGIcon>
|
15
src/components/icons/brands/IconWeasyl.astro
Normal file
15
src/components/icons/brands/IconWeasyl.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 24 24">
|
||||
<path
|
||||
d="M21.23 4.156a8.488 8.488 0 0 0-5.871-1.857c-3.766.243-6.324 2.662-7.364 6.481-1.28-1.224-1.892-3.238-2.093-5.54-1.02.215-1.658.702-2.233 1.237.445 2.316 1.802 4.015 3.264 5.158-2.559.317-5.99 2.442-6.771 4.904-.507 1.598.258 3.415 1.283 4.52 1.237 1.333 3.75 1.998 6.355 1.754.037.362-.104.536-.058.907 4.067-.306 7.174-1.646 10.04-3.894 1.119-.877 2.659-2.037 3.756-3.227 1.101-1.192 2.296-2.578 2.443-4.52.21-2.79-1.236-4.694-2.751-5.923zm-1.434 10.938c-1.035 1.001-2.241 1.797-3.351 2.675-1.249-1.987-2.583-3.984-3.887-5.917.017 2.63.006 5.432.04 7.957-.78.381-1.789.558-2.744.763-1.935-2.917-3.968-5.99-5.961-8.908.693-.447 1.627-.785 2.478-1.075 1.419 2.05 2.729 4.253 4.171 6.333.019-3.113-.009-6.673-.061-9.919a14.175 14.175 0 0 0 1.527-.434c1.813 2.721 3.553 5.628 5.464 8.359a547.35 547.35 0 0 1-.018-9.768c.858-.282 1.803-.535 2.669-.809.02 3.499-.338 7.128-.327 10.743z"
|
||||
></path>
|
||||
</SVGIcon>
|
5
src/components/icons/brands/index.ts
Normal file
5
src/components/icons/brands/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export { default as IconEkasPortal } from "./IconEkasPortal.astro";
|
||||
export { default as IconFurAffinity } from "./IconFurAffinity.astro";
|
||||
export { default as IconInkbunny } from "./IconInkbunny.astro";
|
||||
export { default as IconSoFurry } from "./IconSoFurry.astro";
|
||||
export { default as IconWeasyl } from "./IconWeasyl.astro";
|
2
src/content/blog/drafts/.gitignore
vendored
Normal file
2
src/content/blog/drafts/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -78,6 +78,14 @@ const websiteLinks = z.object({
|
|||
return { link, username };
|
||||
}),
|
||||
),
|
||||
sofurrybeta: z.object({ link: z.string().url(), username: z.string() }).or(
|
||||
z.string().transform((link, ctx) => {
|
||||
const { username } = parseRegex<{ username: string }>(
|
||||
/^(?:https?:\/\/)?sofurrybeta.com\/u\/(?<username>[^\/]+)\/?$/,
|
||||
)(link, ctx);
|
||||
return { link, username };
|
||||
}),
|
||||
),
|
||||
mastodon: z
|
||||
.object({ link: z.string().url(), username: z.string().regex(/^[^@]+@[^@]+$/) })
|
||||
.or(
|
||||
|
@ -144,7 +152,6 @@ const publishedContent = z.object({
|
|||
// Required parameters
|
||||
title: z.string(),
|
||||
authors: userList,
|
||||
contentWarning: z.string().trim(),
|
||||
// Required parameters, but optional for drafts (isDraft === true)
|
||||
pubDate: z
|
||||
.date()
|
||||
|
@ -154,10 +161,10 @@ const publishedContent = z.object({
|
|||
tags: z.array(z.string()),
|
||||
// Optional parameters
|
||||
isDraft: z.boolean().default(false),
|
||||
isAgeRestricted: z.boolean().default(true),
|
||||
relatedStories: z.array(reference("stories")).default([]),
|
||||
relatedGames: z.array(reference("games")).default([]),
|
||||
lang: lang,
|
||||
copyrightedCharacters: copyrightedCharacters,
|
||||
series: reference("series").optional(),
|
||||
posts: z
|
||||
.object({
|
||||
|
@ -191,6 +198,18 @@ const publishedContent = z.object({
|
|||
)(link, ctx);
|
||||
return { link, postId };
|
||||
}),
|
||||
sofurrybeta: z.string().transform((link, ctx) => {
|
||||
const { postId } = parseRegex<{ postId: string }>(
|
||||
/^(?:https?:\/\/)sofurrybeta\.com\/s\/(?<postId>[a-zA-Z0-9]+)\/?$/,
|
||||
)(link, ctx);
|
||||
return { link, postId };
|
||||
}),
|
||||
itch: z.string().transform((link, ctx) => {
|
||||
const { user, postId } = parseRegex<{ user: string; postId: string }>(
|
||||
/^(?:https?:\/\/)(?<user>[a-z-]+)\.itch\.io\/(?<postId>[a-z0-9_-]+)\/?$/,
|
||||
)(link, ctx);
|
||||
return { link, user, postId };
|
||||
}),
|
||||
twitter: z.string().transform((link, ctx) => {
|
||||
const { user, postId } = parseRegex<{ user: string; postId: string }>(
|
||||
/^(?:https?:\/\/)(?:www\.)?(?:twitter\.com|x\.com)\/(?<user>[a-zA-Z0-9_-]+)\/status\/(?<postId>[1-9]\d*)\/?$/,
|
||||
|
@ -212,6 +231,7 @@ const publishedContent = z.object({
|
|||
})
|
||||
.partial()
|
||||
.default({}),
|
||||
blacklistedMastodonComments: z.array(z.string()).default([]),
|
||||
});
|
||||
|
||||
// Types
|
||||
|
@ -232,17 +252,19 @@ const storiesCollection = defineCollection({
|
|||
z
|
||||
.object({
|
||||
// Required parameters, but optional for drafts (isDraft === true)
|
||||
contentWarning: z.string().trim(),
|
||||
wordCount: z.number().int().optional(),
|
||||
thumbnail: image().optional(),
|
||||
// Optional parameters
|
||||
shortTitle: z.string().optional(),
|
||||
commissioners: userList.optional(),
|
||||
requesters: userList.optional(),
|
||||
summary: z.string().trim().optional(),
|
||||
thumbnailWidth: z.number().int().optional(),
|
||||
thumbnailHeight: z.number().int().optional(),
|
||||
prev: reference("stories").nullish(),
|
||||
next: reference("stories").nullish(),
|
||||
copyrightedCharacters: copyrightedCharacters,
|
||||
shortTitle: z.string().optional(),
|
||||
commissioners: userList.optional(),
|
||||
requesters: userList.optional(),
|
||||
summary: z.string().trim().optional(),
|
||||
})
|
||||
.and(publishedContent)
|
||||
.refine(({ isDraft, description }) => isDraft || description, `Missing "description" for published story`)
|
||||
|
@ -253,7 +275,11 @@ const storiesCollection = defineCollection({
|
|||
.refine(({ isDraft, wordCount }) => isDraft || wordCount, `Missing "wordCount" for published story`)
|
||||
.refine(({ isDraft, pubDate }) => isDraft || pubDate, `Missing "pubDate" for published story`)
|
||||
.refine(({ isDraft, thumbnail }) => isDraft || thumbnail, `Missing "thumbnail" for published story`)
|
||||
.refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published story`),
|
||||
.refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published story`)
|
||||
.refine(
|
||||
({ posts, blacklistedMastodonComments }) => !blacklistedMastodonComments.length || posts.mastodon,
|
||||
`Cannot include "blacklistedMastodonComments" without a Mastodon post`,
|
||||
),
|
||||
});
|
||||
|
||||
const gamesCollection = defineCollection({
|
||||
|
@ -262,6 +288,7 @@ const gamesCollection = defineCollection({
|
|||
z
|
||||
.object({
|
||||
// Required parameters, but optional for drafts (isDraft === true)
|
||||
contentWarning: z.string().trim(),
|
||||
platforms: z.array(platform).default([]),
|
||||
thumbnail: image().optional(),
|
||||
// Optional parameters
|
||||
|
@ -269,6 +296,7 @@ const gamesCollection = defineCollection({
|
|||
thumbnailHeight: z.number().int().optional(),
|
||||
prev: reference("games").nullish(),
|
||||
next: reference("games").nullish(),
|
||||
copyrightedCharacters: copyrightedCharacters,
|
||||
})
|
||||
.and(publishedContent)
|
||||
.refine(({ isDraft, description }) => isDraft || description, `Missing "description" for published game`)
|
||||
|
@ -276,7 +304,36 @@ const gamesCollection = defineCollection({
|
|||
.refine(({ isDraft, platforms }) => isDraft || platforms.length, `Missing "platforms" for published game`)
|
||||
.refine(({ isDraft, pubDate }) => isDraft || pubDate, `Missing "pubDate" for published game`)
|
||||
.refine(({ isDraft, thumbnail }) => isDraft || thumbnail, `Missing "thumbnail" for published game`)
|
||||
.refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published game`),
|
||||
.refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published game`)
|
||||
.refine(
|
||||
({ posts, blacklistedMastodonComments }) => !blacklistedMastodonComments.length || posts.mastodon,
|
||||
`Cannot include "blacklistedMastodonComments" without a Mastodon post`,
|
||||
),
|
||||
});
|
||||
|
||||
const blogCollection = defineCollection({
|
||||
type: "content",
|
||||
schema: ({ image }) =>
|
||||
z
|
||||
.object({
|
||||
// Required parameters, but optional for drafts (isDraft === true)
|
||||
thumbnail: image().optional(),
|
||||
// Optional parameters
|
||||
summary: z.string().trim().optional(),
|
||||
thumbnailWidth: z.number().int().optional(),
|
||||
thumbnailHeight: z.number().int().optional(),
|
||||
prev: reference("blog").nullish(),
|
||||
next: reference("blog").nullish(),
|
||||
})
|
||||
.and(publishedContent)
|
||||
.refine(({ isDraft, description }) => isDraft || description, `Missing "description" for published story`)
|
||||
.refine(({ isDraft, pubDate }) => isDraft || pubDate, `Missing "pubDate" for published story`)
|
||||
.refine(({ isDraft, thumbnail }) => isDraft || thumbnail, `Missing "thumbnail" for published story`)
|
||||
.refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published story`)
|
||||
.refine(
|
||||
({ posts, blacklistedMastodonComments }) => !blacklistedMastodonComments.length || posts.mastodon,
|
||||
`Cannot include "blacklistedMastodonComments" without a Mastodon post`,
|
||||
),
|
||||
});
|
||||
|
||||
// Data collections
|
||||
|
@ -332,6 +389,7 @@ const tagCategoriesCollection = defineCollection({
|
|||
export const collections = {
|
||||
stories: storiesCollection,
|
||||
games: gamesCollection,
|
||||
blog: blogCollection,
|
||||
users: usersCollection,
|
||||
series: seriesCollection,
|
||||
"tag-categories": tagCategoriesCollection,
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245838/accommodation-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009993
|
||||
sofurry: https://www.sofurry.com/view/1992347
|
||||
sofurrybeta: https://sofurrybeta.com/s/dmBBW6Zm
|
||||
tags:
|
||||
- anal vore
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245835/c-addictive-additions-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009992
|
||||
sofurry: https://www.sofurry.com/view/1992344
|
||||
sofurrybeta: https://sofurrybeta.com/s/ZmM3E4q1
|
||||
tags:
|
||||
- oral vore
|
||||
- anal vore
|
||||
|
@ -30,6 +31,7 @@ tags:
|
|||
- semi-willing prey
|
||||
- similar size
|
||||
- implied perma endo
|
||||
- endo trait theft
|
||||
- straight sex
|
||||
- gay sex
|
||||
- hyper
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245812/annivoresary-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009934
|
||||
sofurry: https://www.sofurry.com/view/1992300
|
||||
sofurrybeta: https://sofurrybeta.com/s/3egLylPm
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245853/c-better-in-bully-batter-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010009
|
||||
sofurry: https://www.sofurry.com/view/1992371
|
||||
sofurrybeta: https://sofurrybeta.com/s/dmW3GPwm
|
||||
tags:
|
||||
- cock vore
|
||||
- anthro predator
|
||||
|
@ -27,6 +28,7 @@ tags:
|
|||
- unwilling prey
|
||||
- similar size
|
||||
- implied perma endo
|
||||
- endo trait theft
|
||||
- straight sex
|
||||
- gay sex
|
||||
- orgy
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2326739/big-haul-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3179339
|
||||
sofurry: https://www.sofurry.com/view/2074207
|
||||
sofurrybeta: https://sofurrybeta.com/s/GnDLVoGn
|
||||
tags:
|
||||
- unbirth
|
||||
- anthro predator
|
||||
|
|
|
@ -18,6 +18,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245859/birdroom-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010032
|
||||
sofurry: https://www.sofurry.com/view/1992379
|
||||
sofurrybeta: https://sofurrybeta.com/s/7ejYXvL1
|
||||
tags:
|
||||
- Sam Brendan
|
||||
- Beetle
|
||||
|
|
|
@ -18,6 +18,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2322878/bladder-filler-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3168729
|
||||
sofurry: https://www.sofurry.com/view/2069991
|
||||
sofurrybeta: https://sofurrybeta.com/s/J1O5Z3zm
|
||||
tags:
|
||||
- Beetle
|
||||
- cock vore
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2308019/bottom-of-the-food-chain-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3130702
|
||||
sofurry: https://www.sofurry.com/view/2054568
|
||||
sofurrybeta: https://sofurrybeta.com/s/Vm2b34Gm
|
||||
tags:
|
||||
- Muno
|
||||
- oral vore
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245850/butting-into-their-plans-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010005
|
||||
sofurry: https://www.sofurry.com/view/1992365
|
||||
sofurrybeta: https://sofurrybeta.com/s/znJE5M3m
|
||||
tags:
|
||||
- anal vore
|
||||
- feral predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245840/delicacy-s-dare-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009994
|
||||
sofurry: https://www.sofurry.com/view/1992348
|
||||
sofurrybeta: https://sofurrybeta.com/s/V1YARGy1
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245808/eggs-for-months-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009928
|
||||
sofurry: https://www.sofurry.com/view/1992262
|
||||
sofurrybeta: https://sofurrybeta.com/s/lmXB9VG1
|
||||
tags:
|
||||
- sheath vore
|
||||
- feral predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2291372/engaging-contacts-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3088451
|
||||
sofurry: https://www.sofurry.com/view/2035092
|
||||
sofurrybeta: https://sofurrybeta.com/s/YnLrbBpe
|
||||
tags:
|
||||
- oral vore
|
||||
- unbirth
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245855/flavorful-favor-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010014
|
||||
sofurry: https://www.sofurry.com/view/1992375
|
||||
sofurrybeta: https://sofurrybeta.com/s/WelWOaj1
|
||||
tags:
|
||||
- Beetle
|
||||
- oral vore
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245830/for-the-night-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009989
|
||||
sofurry: https://www.sofurry.com/view/1992339
|
||||
sofurrybeta: https://sofurrybeta.com/s/P1EMLv81
|
||||
tags:
|
||||
- anal vore
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2320112/gentle-and-cruel-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3161450
|
||||
sofurry: https://www.sofurry.com/view/2066780
|
||||
sofurrybeta: https://sofurrybeta.com/s/3egLyEdm
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245852/hate-to-sea-it-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010007
|
||||
sofurry: https://www.sofurry.com/view/1992369
|
||||
sofurrybeta: https://sofurrybeta.com/s/pnGE786e
|
||||
tags:
|
||||
- unbirth
|
||||
- feral predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245845/hungry-for-love-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010001
|
||||
sofurry: https://www.sofurry.com/view/1992358
|
||||
sofurrybeta: https://sofurrybeta.com/s/pnGE787e
|
||||
tags:
|
||||
- oral vore
|
||||
- feral predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245818/hyper-hunger-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009945
|
||||
sofurry: https://www.sofurry.com/view/1992317
|
||||
sofurrybeta: https://sofurrybeta.com/s/JewQ7gYn
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245823/insistence-and-assistance-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009949
|
||||
sofurry: https://www.sofurry.com/view/1992324
|
||||
sofurrybeta: https://sofurrybeta.com/s/A1pxJED1
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245829/lactation-action-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009986
|
||||
sofurry: https://www.sofurry.com/view/1992335
|
||||
sofurrybeta: https://sofurrybeta.com/s/0mvw0ZQn
|
||||
tags:
|
||||
- nipple vore
|
||||
- oral vore
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245828/latest-catch-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009984
|
||||
sofurry: https://www.sofurry.com/view/1992331
|
||||
sofurrybeta: https://sofurrybeta.com/s/rn6Jyzpn
|
||||
tags:
|
||||
- cock vore
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245821/never-too-late-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009947
|
||||
sofurry: https://www.sofurry.com/view/1992320
|
||||
sofurrybeta: https://sofurrybeta.com/s/5nz8gOle
|
||||
tags:
|
||||
- cock vore
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2305403/noble-fire-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3124162
|
||||
sofurry: https://www.sofurry.com/view/2051777
|
||||
sofurrybeta: https://sofurrybeta.com/s/lmXB9qy1
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2291367/r-overzealous-zenko-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3088442
|
||||
sofurry: https://www.sofurry.com/view/2035087
|
||||
sofurrybeta: https://sofurrybeta.com/s/Xek5wP5n
|
||||
tags:
|
||||
- chest maw vore
|
||||
- taur predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2257653/part-of-the-show-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3030429
|
||||
sofurry: https://www.sofurry.com/view/2001881
|
||||
sofurrybeta: https://sofurrybeta.com/s/r17DQXBe
|
||||
tags:
|
||||
- Sam Brendan
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245810/pet-sit-saturday-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009931
|
||||
sofurry: https://www.sofurry.com/view/1992266
|
||||
sofurrybeta: https://sofurrybeta.com/s/qmywZNW1
|
||||
tags:
|
||||
- anal vore
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
furaffinity: https://www.furaffinity.net/view/57675502/
|
||||
inkbunny: https://inkbunny.net/s/3391838
|
||||
sofurry: https://www.sofurry.com/view/2161474
|
||||
sofurrybeta: https://sofurrybeta.com/s/dmBBkvXm
|
||||
weasyl: https://www.weasyl.com/~badmanners/submissions/2401625/playing-it-safe
|
||||
twitter: https://x.com/BadManners__/status/1821526198150680589
|
||||
bluesky: https://bsky.app/profile/badmanners.xyz/post/3kz7gvvwyvt2c
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245847/reaching-for-the-full-moon-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010003
|
||||
sofurry: https://www.sofurry.com/view/1992360
|
||||
sofurrybeta: https://sofurrybeta.com/s/V1YARWD1
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -15,6 +15,7 @@ posts:
|
|||
furaffinity: https://www.furaffinity.net/view/57459926/
|
||||
inkbunny: https://inkbunny.net/s/3377727
|
||||
sofurry: https://www.sofurry.com/view/2156241
|
||||
sofurrybeta: https://sofurrybeta.com/s/ZmM3QrW1
|
||||
weasyl: https://www.weasyl.com/~badmanners/submissions/2396279/c-rose-s-binge
|
||||
mastodon: https://meow.social/@BadManners/112827108738415986
|
||||
tags:
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245848/ruffling-some-feathers-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010004
|
||||
sofurry: https://www.sofurry.com/view/1992363
|
||||
sofurrybeta: https://sofurrybeta.com/s/k1VYoGDn
|
||||
tags:
|
||||
- Muno
|
||||
- oral vore
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245831/spontaneous-sleepover-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009991
|
||||
sofurry: https://www.sofurry.com/view/1992340
|
||||
sofurrybeta: https://sofurrybeta.com/s/rm8DNdqm
|
||||
tags:
|
||||
- tail vore
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2345545/taken-in
|
||||
inkbunny: https://inkbunny.net/s/3231516
|
||||
sofurry: https://www.sofurry.com/view/2096828
|
||||
sofurrybeta: https://sofurrybeta.com/s/B1QQYaz1
|
||||
tags:
|
||||
- Sam Brendan
|
||||
- feral predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245857/tasting-high-consequences-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3010016
|
||||
sofurry: https://www.sofurry.com/view/1992377
|
||||
sofurrybeta: https://sofurrybeta.com/s/Oe5RNpMm
|
||||
tags:
|
||||
- oral vore
|
||||
- feral predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2341116/c-team-building
|
||||
inkbunny: https://inkbunny.net/s/3219382
|
||||
sofurry: https://www.sofurry.com/view/2091230
|
||||
sofurrybeta: https://sofurrybeta.com/s/RnoXYox1
|
||||
tags:
|
||||
- cock vore
|
||||
- anal vore
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2291370/r-team-effort-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3088444
|
||||
sofurry: https://www.sofurry.com/view/2035089
|
||||
sofurrybeta: https://sofurrybeta.com/s/ynZ7L8w1
|
||||
tags:
|
||||
- cock vore
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245824/the-last-livestream-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009975
|
||||
sofurry: https://www.sofurry.com/view/1992325
|
||||
sofurrybeta: https://sofurrybeta.com/s/B1QQYK71
|
||||
tags:
|
||||
- unbirth
|
||||
- anthro predator
|
||||
|
|
|
@ -17,6 +17,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245842/the-lost-of-the-marshes-bonus-quince-s-fantasy
|
||||
inkbunny: https://inkbunny.net/s/3009997
|
||||
sofurry: https://www.sofurry.com/view/1992350
|
||||
sofurrybeta: https://sofurrybeta.com/s/k1VYoJGn
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -15,6 +15,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245800/the-lost-of-the-marshes-chapter-1-found
|
||||
inkbunny: https://inkbunny.net/s/3009918
|
||||
sofurry: https://www.sofurry.com/view/1992256
|
||||
sofurrybeta: https://sofurrybeta.com/s/Rm0K4OKe
|
||||
tags:
|
||||
- oral vore
|
||||
- feral predator
|
||||
|
|
|
@ -17,6 +17,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245861/the-lost-of-the-marshes-chapter-10-memory
|
||||
inkbunny: https://inkbunny.net/s/3010039
|
||||
sofurry: https://www.sofurry.com/view/1992381
|
||||
sofurrybeta: https://sofurrybeta.com/s/ve3QaApn
|
||||
tags:
|
||||
- oral vore
|
||||
- anal vore
|
||||
|
|
|
@ -15,6 +15,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2325367/the-lost-of-the-marshes-chapter-11-familiar
|
||||
inkbunny: https://inkbunny.net/s/3175040
|
||||
sofurry: https://www.sofurry.com/view/2072674
|
||||
sofurrybeta: https://sofurrybeta.com/s/RnoXYo01
|
||||
tags:
|
||||
- oral vore
|
||||
- cock vore
|
||||
|
|
|
@ -17,6 +17,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245802/the-lost-of-the-marshes-chapter-2-trust
|
||||
inkbunny: https://inkbunny.net/s/3009921
|
||||
sofurry: https://www.sofurry.com/view/1992257
|
||||
sofurrybeta: https://sofurrybeta.com/s/dePdgr5e
|
||||
tags:
|
||||
- oral vore
|
||||
- feral predator
|
||||
|
|
|
@ -17,6 +17,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245804/the-lost-of-the-marshes-chapter-3-home
|
||||
inkbunny: https://inkbunny.net/s/3009926
|
||||
sofurry: https://www.sofurry.com/view/1992259
|
||||
sofurrybeta: https://sofurrybeta.com/s/q1xJz8Zm
|
||||
tags:
|
||||
- oral vore
|
||||
- macro predator
|
||||
|
|
|
@ -19,6 +19,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245805/the-lost-of-the-marshes-chapter-4-change
|
||||
inkbunny: https://inkbunny.net/s/3009927
|
||||
sofurry: https://www.sofurry.com/view/1992260
|
||||
sofurrybeta: https://sofurrybeta.com/s/ynd4LA7n
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -19,6 +19,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245811/the-lost-of-the-marshes-chapter-5-intersection
|
||||
inkbunny: https://inkbunny.net/s/3009933
|
||||
sofurry: https://www.sofurry.com/view/1992297
|
||||
sofurrybeta: https://sofurrybeta.com/s/zeRb9Nge
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -17,6 +17,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245813/the-lost-of-the-marshes-chapter-6-pleasure
|
||||
inkbunny: https://inkbunny.net/s/3009938
|
||||
sofurry: https://www.sofurry.com/view/1992302
|
||||
sofurrybeta: https://sofurrybeta.com/s/J1O5Zqgm
|
||||
tags:
|
||||
- oral vore
|
||||
- unbirth
|
||||
|
|
|
@ -17,6 +17,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245817/the-lost-of-the-marshes-chapter-7-honesty
|
||||
inkbunny: https://inkbunny.net/s/3009943
|
||||
sofurry: https://www.sofurry.com/view/1992307
|
||||
sofurrybeta: https://sofurrybeta.com/s/GnDLVbjn
|
||||
tags:
|
||||
- oral vore
|
||||
- anal vore
|
||||
|
|
|
@ -15,6 +15,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245827/the-lost-of-the-marshes-chapter-8-estranged
|
||||
inkbunny: https://inkbunny.net/s/3009983
|
||||
sofurry: https://www.sofurry.com/view/1992326
|
||||
sofurrybeta: https://sofurrybeta.com/s/rn92NpQ1
|
||||
tags:
|
||||
- oral vore
|
||||
- anal vore
|
||||
|
|
|
@ -15,6 +15,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245844/the-lost-of-the-marshes-chapter-9-stuck
|
||||
inkbunny: https://inkbunny.net/s/3010000
|
||||
sofurry: https://www.sofurry.com/view/1992354
|
||||
sofurrybeta: https://sofurrybeta.com/s/znJE5M7m
|
||||
tags:
|
||||
- oral vore
|
||||
- slit vore
|
||||
|
|
|
@ -15,6 +15,7 @@ posts:
|
|||
furaffinity: https://www.furaffinity.net/view/56026627/
|
||||
inkbunny: https://inkbunny.net/s/3283508
|
||||
sofurry: https://www.sofurry.com/view/2118138
|
||||
sofurrybeta: https://sofurrybeta.com/s/0mvwLB0n
|
||||
weasyl: https://www.weasyl.com/~badmanners/submissions/2363560/tiny-accident
|
||||
bluesky: https://bsky.app/profile/badmanners.xyz/post/3kok52wijz32c
|
||||
mastodon: https://meow.social/@BadManners/112157812554023271
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245854/tomo-moku-lipu-pi-moku-musi
|
||||
inkbunny: https://inkbunny.net/s/3010010
|
||||
sofurry: https://www.sofurry.com/view/1992374
|
||||
sofurrybeta: https://sofurrybeta.com/s/4nAMWvAn
|
||||
tags:
|
||||
- oral vore
|
||||
- ambiguous predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2305405/trouble-sleeping-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3124166
|
||||
sofurry: https://www.sofurry.com/view/2051787
|
||||
sofurrybeta: https://sofurrybeta.com/s/qmywZjQ1
|
||||
tags:
|
||||
- unbirth
|
||||
- anthro predator
|
||||
|
|
|
@ -16,6 +16,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2291371/r-warped-friendship-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3088450
|
||||
sofurry: https://www.sofurry.com/view/2035090
|
||||
sofurrybeta: https://sofurrybeta.com/s/AnKr5QPm
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2331157/c-within-limits
|
||||
inkbunny: https://inkbunny.net/s/3191950
|
||||
sofurry: https://www.sofurry.com/view/2079346
|
||||
sofurrybeta: https://sofurrybeta.com/s/J1O5Z3km
|
||||
tags:
|
||||
- unbirth
|
||||
- cock vore
|
||||
|
|
|
@ -19,6 +19,7 @@ posts:
|
|||
furaffinity: https://www.furaffinity.net/view/57459921/
|
||||
inkbunny: https://inkbunny.net/s/3377722
|
||||
sofurry: https://www.sofurry.com/view/2156237
|
||||
sofurrybeta: https://sofurrybeta.com/s/rm8DBRWm
|
||||
weasyl: https://www.weasyl.com/~badmanners/submissions/2396278/woofer-exploration
|
||||
mastodon: https://meow.social/@BadManners/112827104119035982
|
||||
tags:
|
||||
|
|
|
@ -14,6 +14,7 @@ posts:
|
|||
weasyl: https://www.weasyl.com/~badmanners/submissions/2245815/you-re-home-vore-story
|
||||
inkbunny: https://inkbunny.net/s/3009942
|
||||
sofurry: https://www.sofurry.com/view/1992304
|
||||
sofurrybeta: https://sofurrybeta.com/s/RnoXY6o1
|
||||
tags:
|
||||
- oral vore
|
||||
- anthro predator
|
||||
|
|
|
@ -65,5 +65,9 @@ tags:
|
|||
- cock vore
|
||||
- name: soul vore
|
||||
description: Scenarios where predators consume a soul instead of their prey's body.
|
||||
- name: endo trait theft
|
||||
description: Scenarios where predators acquire traits from their prey without digestion.
|
||||
related:
|
||||
- transformation
|
||||
- name: Vore Day
|
||||
description: Stories created in commemoration of Vore Day, which is celebrated on August 8th, and/or are set in said day.
|
||||
|
|
|
@ -9,6 +9,8 @@ tags:
|
|||
- object vore
|
||||
- name: transformation
|
||||
description: Scenarios where a character changes body and/or species.
|
||||
related:
|
||||
- endo trait theft
|
||||
- name: netorare
|
||||
description: Scenarios involving a character cheating on their partner with or without consent, and/or cuckoldry.
|
||||
- name: sizeplay
|
||||
|
|
|
@ -10,6 +10,7 @@ links:
|
|||
sofurry:
|
||||
link: https://bad-manners.sofurry.com/
|
||||
username: Bad Manners
|
||||
sofurrybeta: https://sofurrybeta.com/u/BadManners
|
||||
weasyl: https://www.weasyl.com/~BadManners
|
||||
twitter: https://twitter.com/BadManners__
|
||||
mastodon: https://meow.social/@BadManners
|
||||
|
|
|
@ -51,6 +51,34 @@ author = "Noto Project Authors"
|
|||
source = "https://github.com/notofonts/latin-greek-cyrillic"
|
||||
license = { name = "SIL Open Font License v1.1", url = "https://opensource.org/license/ofl-1-1" }
|
||||
|
||||
[[attributions]]
|
||||
author = "Simple Icons"
|
||||
description = "Icons for third-party brands."
|
||||
type = "icons"
|
||||
source = "https://simpleicons.org"
|
||||
license = { name = "CC0 1.0 Universal", url = "https://creativecommons.org/publicdomain/zero/1.0/" }
|
||||
items = [
|
||||
"Weasyl",
|
||||
]
|
||||
notes = """All third-party copyrights and trademarks belong to their respective owners, \
|
||||
and I'm not affiliated with any of them."""
|
||||
|
||||
[[attributions]]
|
||||
description = "Edited icons for other websites."
|
||||
type = "icons"
|
||||
author = { name = "Bad Manners", url = "https://badmanners.xyz", email = "me@badmanners.xyz>" }
|
||||
source = "https://git.badmanners.xyz/badmanners/badmanners.xyz/src/branch/main/src/components/icons/brands"
|
||||
license = { name = "CC0 1.0 Universal", url = "https://creativecommons.org/publicdomain/zero/1.0/" }
|
||||
items = [
|
||||
"Eka's Portal",
|
||||
"Fur Affinity",
|
||||
"Inkbunny",
|
||||
"SoFurry",
|
||||
]
|
||||
notes = """Original icons edited for personal use and released under a permissive license.
|
||||
All third-party copyrights and trademarks belong to their respective owners, \
|
||||
and I'm not affiliated with any of them."""
|
||||
|
||||
[[attributions]]
|
||||
author = "Font Awesome"
|
||||
description = "Generic icons."
|
||||
|
|
|
@ -113,6 +113,30 @@ const UI_STRINGS = {
|
|||
en: "Click to reveal",
|
||||
tok: "Click to reveal summary in English",
|
||||
},
|
||||
"published_content/syndication_see_also_on": {
|
||||
en: "See also on...",
|
||||
tok: "o lukin lon ma ante",
|
||||
},
|
||||
"published_content/syndication_eka": {
|
||||
en: "Eka's Portal",
|
||||
tok: "lipu Ikapoto",
|
||||
},
|
||||
"published_content/syndication_furaffinity": {
|
||||
en: "Fur Affinity",
|
||||
tok: "lipu Panapinisi",
|
||||
},
|
||||
"published_content/syndication_inkbunny": {
|
||||
en: "Inkbunny",
|
||||
tok: "lipu Inpani",
|
||||
},
|
||||
"published_content/syndication_sofurry": {
|
||||
en: "SoFurry",
|
||||
tok: "lipu Sopanli",
|
||||
},
|
||||
"published_content/syndication_weasyl": {
|
||||
en: "Weasyl",
|
||||
tok: "lipu Wise",
|
||||
},
|
||||
// Story page-specific strings
|
||||
"story/return_to_stories": {
|
||||
en: "Return to stories",
|
||||
|
|
|
@ -7,9 +7,10 @@ import AgeRestrictedModal from "../components/AgeRestrictedModal.astro";
|
|||
type Props = {
|
||||
pageTitle: string;
|
||||
lang?: string;
|
||||
isAgeRestricted: boolean;
|
||||
};
|
||||
|
||||
const { pageTitle, lang = "en" } = Astro.props;
|
||||
const { pageTitle, lang = "en", isAgeRestricted } = Astro.props;
|
||||
---
|
||||
|
||||
<html lang={lang}>
|
||||
|
@ -38,6 +39,6 @@ const { pageTitle, lang = "en" } = Astro.props;
|
|||
<body>
|
||||
<slot />
|
||||
<DarkModeScript />
|
||||
<AgeRestrictedModal />
|
||||
{isAgeRestricted ? <AgeRestrictedModal /> : null}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -17,18 +17,19 @@ import {
|
|||
|
||||
type Props = {
|
||||
pageTitle: string;
|
||||
isAgeRestricted?: boolean;
|
||||
enablePagefind?: boolean;
|
||||
class?: string;
|
||||
};
|
||||
|
||||
const { pageTitle, enablePagefind, class: className } = Astro.props;
|
||||
const { pageTitle, enablePagefind, class: className, isAgeRestricted } = Astro.props;
|
||||
const logo = await getImage({ src: logoBM, width: 192 });
|
||||
const currentYear = new Date().getFullYear().toString();
|
||||
const isCurrentRoute = (path: string) =>
|
||||
Astro.url.pathname === path || (path !== "/" && Astro.url.pathname === `${path}/`);
|
||||
---
|
||||
|
||||
<BaseLayout pageTitle={pageTitle}>
|
||||
<BaseLayout pageTitle={pageTitle} isAgeRestricted={isAgeRestricted ?? true}>
|
||||
<Fragment slot="head">
|
||||
<meta property="og:title" content={pageTitle || "Bad Manners"} />
|
||||
<meta property="og:url" content={Astro.url} />
|
||||
|
|
|
@ -22,6 +22,7 @@ const relatedGames = (await getEntries(props.relatedGames)).filter((game) => !ga
|
|||
title={props.title}
|
||||
lang={props.lang}
|
||||
isDraft={props.isDraft}
|
||||
isAgeRestricted={props.isAgeRestricted}
|
||||
pubDate={props.pubDate}
|
||||
description={props.description}
|
||||
summary={undefined}
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
IconChevronRight,
|
||||
IconArrowUp,
|
||||
} from "../components/icons";
|
||||
import ExternalPosts from "../components/ExternalPosts.astro";
|
||||
|
||||
interface RelatedContent {
|
||||
link: string;
|
||||
|
@ -31,6 +32,7 @@ type Props = {
|
|||
title: string;
|
||||
lang: Lang;
|
||||
isDraft: boolean;
|
||||
isAgeRestricted: boolean;
|
||||
pubDate?: Date;
|
||||
description: string;
|
||||
summary?: string;
|
||||
|
@ -88,7 +90,7 @@ const returnTo = series
|
|||
: props.labelReturnTo.title;
|
||||
---
|
||||
|
||||
<BaseLayout pageTitle={props.title} lang={props.lang}>
|
||||
<BaseLayout pageTitle={props.title} lang={props.lang} isAgeRestricted={props.isAgeRestricted}>
|
||||
<Fragment slot="head">
|
||||
{props.isDraft ? <meta name="robots" content="noindex" /> : null}
|
||||
<meta property="og:title" content={props.title} data-pagefind-meta="title[content]" />
|
||||
|
@ -153,11 +155,11 @@ const returnTo = series
|
|||
<a
|
||||
href={props.prev.link}
|
||||
rel="prev"
|
||||
class="text-link flex items-center justify-center border-r border-stone-400 px-1 py-3 underline dark:border-stone-600"
|
||||
class="h-entry u-url text-link flex items-center justify-center border-r border-stone-400 px-1 py-3 underline dark:border-stone-600"
|
||||
aria-label={props.labelPreviousContent}
|
||||
>
|
||||
<IconChevronLeft width="1.25rem" height="1.25rem" />
|
||||
<span class="ml-1">{props.prev.title}</span>
|
||||
<span class="p-name ml-1">{props.prev.title}</span>
|
||||
</a>
|
||||
) : (
|
||||
<div class="h-full border-r border-stone-400 dark:border-stone-600" aria-hidden="true" />
|
||||
|
@ -166,10 +168,10 @@ const returnTo = series
|
|||
<a
|
||||
href={props.next.link}
|
||||
rel="next"
|
||||
class="text-link flex items-center justify-center px-1 py-3 underline"
|
||||
class="h-entry u-url text-link flex items-center justify-center px-1 py-3 underline"
|
||||
aria-label={props.labelNextContent}
|
||||
>
|
||||
<span class="mr-1">{props.next.title}</span>
|
||||
<span class="p-name mr-1">{props.next.title}</span>
|
||||
<IconChevronRight width="1.25rem" height="1.25rem" />
|
||||
</a>
|
||||
) : (
|
||||
|
@ -376,6 +378,7 @@ const returnTo = series
|
|||
</section>
|
||||
) : null
|
||||
}
|
||||
<ExternalPosts lang={props.lang} posts={props.posts} />
|
||||
{props.posts.mastodon ? <MastodonComments lang={props.lang} {...props.posts.mastodon} /> : null}
|
||||
</main>
|
||||
<div
|
||||
|
|
|
@ -27,6 +27,7 @@ const wordCount = props.wordCount?.toString();
|
|||
title={props.title}
|
||||
lang={props.lang}
|
||||
isDraft={props.isDraft}
|
||||
isAgeRestricted={props.isAgeRestricted}
|
||||
pubDate={props.pubDate}
|
||||
description={props.description}
|
||||
summary={props.summary}
|
||||
|
|
|
@ -79,8 +79,7 @@ const latestItems: LatestItemsEntry[] = await Promise.all(
|
|||
<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">
|
||||
Glad to see you here. You can expect lots of safe vore/endosoma ahead. Use the navigation menu to navigate through
|
||||
my content.
|
||||
Hey there, welcome to my corner of the Internet! You can expect lots of safe vore/endosoma ahead.
|
||||
</p>
|
||||
<ul class="list-disc pl-8">
|
||||
<li><a class="text-link underline" href="/stories/1">Read my stories!</a></li>
|
||||
|
|
|
@ -80,6 +80,13 @@ export function getWebsiteLinkForUser(
|
|||
return `ib!${getUserDataForWebsite(user, "inkbunny").username}`;
|
||||
}
|
||||
break;
|
||||
case "sofurrybeta":
|
||||
if ("sofurrybeta" in links) {
|
||||
return `@${links.sofurrybeta!.username}`;
|
||||
} else if ("sofurry" in links) {
|
||||
return `[${links.sofurry!.username}](${links.sofurry!.link})`;
|
||||
}
|
||||
break;
|
||||
case "twitter":
|
||||
if ("twitter" in links) {
|
||||
return `@${getUserDataForWebsite(user, "twitter").username}`;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { getCollection, getEntry } from "astro:content";
|
||||
import type { Lang, PostWebsite } from "../content/config";
|
||||
import type { Lang, PostWebsite, UserWebsite } from "../content/config";
|
||||
import { getWebsiteLinkForUser } from "./get_website_link_for_user";
|
||||
import { getUsernameForLang } from "./get_username_for_lang";
|
||||
|
||||
|
@ -56,8 +56,8 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
|
|||
if (!story) {
|
||||
throw new Error(`Couldn't find story with slug "${slug}"`);
|
||||
}
|
||||
if (typeof website === "string" && story.data.posts[website]?.link) {
|
||||
replacements.push(`[${text}](${story.data.posts[website].link})`);
|
||||
if (typeof website === "string" && story.data.posts[website as PostWebsite]?.link) {
|
||||
replacements.push(`[${text}](${story.data.posts[website as PostWebsite]!.link})`);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -66,8 +66,8 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
|
|||
if (!game) {
|
||||
throw new Error(`Couldn't find game with slug "${slug}"`);
|
||||
}
|
||||
if (typeof website === "string" && game.data.posts[website]?.link) {
|
||||
replacements.push(`[${text}](${game.data.posts[website].link})`);
|
||||
if (typeof website === "string" && game.data.posts[website as PostWebsite]?.link) {
|
||||
replacements.push(`[${text}](${game.data.posts[website as PostWebsite]!.link})`);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -78,8 +78,8 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
|
|||
}
|
||||
// If there's a label in the link, use that if possible
|
||||
if (text) {
|
||||
if (typeof website === "string" && user.data.links[website]?.link) {
|
||||
replacements.push(`[${text}](${user.data.links[website].link})`);
|
||||
if (typeof website === "string" && user.data.links[website as UserWebsite]?.link) {
|
||||
replacements.push(`[${text}](${user.data.links[website as UserWebsite]!.link})`);
|
||||
continue;
|
||||
} else if (user.data.preferredLink) {
|
||||
replacements.push(`[${text}](${user.data.links[user.data.preferredLink]!.link})`);
|
||||
|
@ -87,7 +87,9 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
|
|||
}
|
||||
}
|
||||
// Otherwise (i.e. label is empty), use the username for the website
|
||||
replacements.push(getWebsiteLinkForUser(user, website, (user) => getUsernameForLang(user, lang)));
|
||||
replacements.push(
|
||||
getWebsiteLinkForUser(user, website as UserWebsite, (user) => getUsernameForLang(user, lang)),
|
||||
);
|
||||
continue;
|
||||
default:
|
||||
const unknown: never = contentPrefix;
|
||||
|
|
Loading…
Add table
Reference in a new issue