Add more links and improve script checks

This commit is contained in:
Bad Manners 2024-08-20 14:13:49 -03:00
parent 483f406037
commit eccd4d8bfe
12 changed files with 264 additions and 205 deletions

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "badmanners.xyz", "name": "badmanners.xyz",
"version": "2.1.0", "version": "2.1.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "badmanners.xyz", "name": "badmanners.xyz",
"version": "2.1.0", "version": "2.1.1",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@astrojs/check": "^0.9.2", "@astrojs/check": "^0.9.2",

View file

@ -1,7 +1,7 @@
{ {
"name": "badmanners.xyz", "name": "badmanners.xyz",
"type": "module", "type": "module",
"version": "2.1.0", "version": "2.1.1",
"scripts": { "scripts": {
"postinstall": "astro sync", "postinstall": "astro sync",
"dev": "astro dev", "dev": "astro dev",

View file

@ -6,7 +6,7 @@ All attributed artwork is copyrighted by their respective creators and distribut
The Jost* typeface is copyrighted by indestructible type* and is distributed under the SIL Open Font License v1.1: https://opensource.org/license/ofl-1-1 The Jost* typeface is copyrighted by indestructible type* and is distributed under the SIL Open Font License v1.1: https://opensource.org/license/ofl-1-1
The SVG icons for Bluesky, Codeberg, Discord, Itch.io, Keybase, GitHub, GitLab, Mastodon, Picarto, Signal, Steam, Telegram, Twitch, Weasyl, and X were created for the Simple Icons project and are distributed under the Creative Commons Zero v1.0 Universal license: https://creativecommons.org/publicdomain/zero/1.0/ The SVG icons for Bluesky, Codeberg, Discord, Itch.io, Keybase, Ko-fi, GitHub, GitLab, Google, Mastodon, Picarto, Reddit, Signal, Steam, Telegram, Twitch, Weasyl, X, and YouTube were created for the Simple Icons project and are distributed under the Creative Commons Zero v1.0 Universal license: https://creativecommons.org/publicdomain/zero/1.0/
The SVG icons for Cohost, Eka's Portal, Fur Affinity, Inkbunny, Itaku, Neocities, SoFurry, and SubscribeStar were edited by me (Bad Manners) from their respective logos, for personal use. The SVG icons for Cohost, Eka's Portal, Fur Affinity, Inkbunny, Itaku, Neocities, SoFurry, and SubscribeStar were edited by me (Bad Manners) from their respective logos, for personal use.

View file

@ -56,8 +56,12 @@ import IconTriangleExclamation from "./icons/IconTriangleExclamation.astro";
import { ENABLE_VIEW_TRANSITIONS } from "astro:env/client"; import { ENABLE_VIEW_TRANSITIONS } from "astro:env/client";
const ageRestrictedModalSetup = () => { const ageRestrictedModalSetup = () => {
if (localStorage.ageVerified !== "true") { const modal = document.querySelector<HTMLElementTagNameMap["div"]>("body > div#modal-age-restricted");
const modal = document.querySelector<HTMLElementTagNameMap["div"]>("div#modal-age-restricted")!; if (!modal) {
throw new Error("Missing #modal-age-restricted element! Make sure that it's a direct child of body.");
}
let ageVerified: "true" | undefined = localStorage.ageVerified;
if (ageVerified !== "true") {
const rejectButton = modal.querySelector<HTMLElementTagNameMap["button"]>("button[data-modal-reject]")!; const rejectButton = modal.querySelector<HTMLElementTagNameMap["button"]>("button[data-modal-reject]")!;
const onRejectButtonClick = (e: MouseEvent) => { const onRejectButtonClick = (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
@ -69,7 +73,8 @@ import IconTriangleExclamation from "./icons/IconTriangleExclamation.astro";
(e: MouseEvent) => { (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
rejectButton.removeEventListener("click", onRejectButtonClick); rejectButton.removeEventListener("click", onRejectButtonClick);
localStorage.ageVerified = "true"; ageVerified = "true";
localStorage.ageVerified = ageVerified;
document.body.style.overflow = "auto"; document.body.style.overflow = "auto";
document.querySelectorAll("body > :not(#modal-age-restricted)").forEach((el) => el.removeAttribute("inert")); document.querySelectorAll("body > :not(#modal-age-restricted)").forEach((el) => el.removeAttribute("inert"));
modal.style.display = "none"; modal.style.display = "none";

View file

@ -1,4 +1,4 @@
--- ---
--- ---
<script is:inline>function a(){let b=document,c="modal-age-restricted";localStorage.ageVerified!=="true"&&((b.body.style.overflow="hidden"),b.querySelectorAll("body > :not(#"+c+")").forEach(e=>e.setAttribute("inert","true")),(b.getElementById(c).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";localStorage.ageVerified!==d&&((b.body.style.overflow="hidden"),b.querySelectorAll("body > :not("+c+")").forEach(e=>e.setAttribute("inert",d)),(b.querySelector("body > "+c).style.display="block"));}document.addEventListener("astro:after-swap",a);a()</script>

View file

@ -6,27 +6,29 @@ import DarkModeScriptInline from "./DarkModeScriptInline.astro";
<script> <script>
import { ENABLE_VIEW_TRANSITIONS } from "astro:env/client"; import { ENABLE_VIEW_TRANSITIONS } from "astro:env/client";
type ColorScheme = "auto" | "dark" | "light";
const colorSchemeSetup = () => { const colorSchemeSetup = () => {
let colorScheme = localStorage.colorScheme; let colorScheme: ColorScheme | undefined = localStorage.colorScheme;
if (!colorScheme || colorScheme === "auto") { if (!colorScheme || colorScheme === "auto") {
colorScheme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; colorScheme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
} }
const toggleColorScheme = (e: MouseEvent) => {
e.preventDefault();
if (colorScheme === "dark") {
colorScheme = "light";
document.body.classList.remove("dark");
} else {
colorScheme = "dark";
document.body.classList.add("dark");
}
localStorage.colorScheme = colorScheme;
};
document.querySelectorAll<HTMLElementTagNameMap["button"]>("button[data-dark-mode]").forEach((button) => { document.querySelectorAll<HTMLElementTagNameMap["button"]>("button[data-dark-mode]").forEach((button) => {
button.classList.remove("hidden"); button.classList.remove("hidden");
button.style.removeProperty("display"); button.style.removeProperty("display");
button.setAttribute("aria-hidden", "false"); button.setAttribute("aria-hidden", "false");
button.addEventListener("click", (e) => { button.addEventListener("click", toggleColorScheme);
e.preventDefault();
if (colorScheme === "dark") {
colorScheme = "light";
document.body.classList.remove("dark");
} else {
colorScheme = "dark";
document.body.classList.add("dark");
}
localStorage.colorScheme = colorScheme;
});
}); });
}; };
if (ENABLE_VIEW_TRANSITIONS) { if (ENABLE_VIEW_TRANSITIONS) {

View 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="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
></path>
</SVGIcon>

View 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="M23.881 8.948c-.773-4.085-4.859-4.593-4.859-4.593H.723c-.604 0-.679.798-.679.798s-.082 7.324-.022 11.822c.164 2.424 2.586 2.672 2.586 2.672s8.267-.023 11.966-.049c2.438-.426 2.683-2.566 2.658-3.734 4.352.24 7.422-2.831 6.649-6.916zm-11.062 3.511c-1.246 1.453-4.011 3.976-4.011 3.976s-.121.119-.31.023c-.076-.057-.108-.09-.108-.09-.443-.441-3.368-3.049-4.034-3.954-.709-.965-1.041-2.7-.091-3.71.951-1.01 3.005-1.086 4.363.407 0 0 1.565-1.782 3.468-.963 1.904.82 1.832 3.011.723 4.311zm6.173.478c-.928.116-1.682.028-1.682.028V7.284h1.77s1.971.551 1.971 2.638c0 1.913-.985 2.667-2.059 3.015z"
></path>
</SVGIcon>

View 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="M12 0C5.373 0 0 5.373 0 12c0 3.314 1.343 6.314 3.515 8.485l-2.286 2.286C.775 23.225 1.097 24 1.738 24H12c6.627 0 12-5.373 12-12S18.627 0 12 0Zm4.388 3.199c1.104 0 1.999.895 1.999 1.999 0 1.105-.895 2-1.999 2-.946 0-1.739-.657-1.947-1.539v.002c-1.147.162-2.032 1.15-2.032 2.341v.007c1.776.067 3.4.567 4.686 1.363.473-.363 1.064-.58 1.707-.58 1.547 0 2.802 1.254 2.802 2.802 0 1.117-.655 2.081-1.601 2.531-.088 3.256-3.637 5.876-7.997 5.876-4.361 0-7.905-2.617-7.998-5.87-.954-.447-1.614-1.415-1.614-2.538 0-1.548 1.255-2.802 2.803-2.802.645 0 1.239.218 1.712.585 1.275-.79 2.881-1.291 4.64-1.365v-.01c0-1.663 1.263-3.034 2.88-3.207.188-.911.993-1.595 1.959-1.595Zm-8.085 8.376c-.784 0-1.459.78-1.506 1.797-.047 1.016.64 1.429 1.426 1.429.786 0 1.371-.369 1.418-1.385.047-1.017-.553-1.841-1.338-1.841Zm7.406 0c-.786 0-1.385.824-1.338 1.841.047 1.017.634 1.385 1.418 1.385.785 0 1.473-.413 1.426-1.429-.046-1.017-.721-1.797-1.506-1.797Zm-3.703 4.013c-.974 0-1.907.048-2.77.135-.147.015-.241.168-.183.305.483 1.154 1.622 1.964 2.953 1.964 1.33 0 2.47-.81 2.953-1.964.057-.137-.037-.29-.184-.305-.863-.087-1.795-.135-2.769-.135Z"
></path>
</SVGIcon>

View 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="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
></path>
</SVGIcon>

View file

@ -5,37 +5,36 @@ const htaccess = `
ErrorDocument 404 /404.html ErrorDocument 404 /404.html
RedirectMatch 301 ^/tos(\/(index.html)?)?$ /terms_of_service/ RedirectMatch 301 ^/tos(\/(index.html)?)?$ /terms_of_service/
RedirectMatch 301 ^/contact(\/(index.html)?)?$ / RedirectMatch 301 ^/contact(\/(index.html)?)?$ /
Redirect 301 /@/aryion https://aryion.com/g4/user/BadManners RedirectMatch 301 ^/@/(aryion|ekas?)\b https://aryion.com/g4/user/BadManners
Redirect 301 /@/eka https://aryion.com/g4/user/BadManners RedirectMatch 301 ^/@/(bluesky|bsky)\b https://bsky.app/profile/badmanners.xyz
Redirect 301 /@/bluesky https://bsky.app/profile/badmanners.xyz RedirectMatch 301 ^/@/(buymeacoffee|bmac)\b https://www.buymeacoffee.com/BadMannersXYZ
Redirect 301 /@/bsky https://bsky.app/profile/badmanners.xyz RedirectMatch 301 ^/@/carrd\b https://badmanners.carrd.co
Redirect 301 /@/codeberg https://codeberg.org/BadManners RedirectMatch 301 ^/@/codeberg\b https://codeberg.org/BadManners
Redirect 301 /@/cohost https://cohost.org/BadManners RedirectMatch 301 ^/@/cohost\b https://cohost.org/BadManners
Redirect 301 /@/fa https://www.furaffinity.net/user/badmanners RedirectMatch 301 ^/@/(fur[_-]?affinity|fa)\b https://www.furaffinity.net/user/badmanners
Redirect 301 /@/furaffinity https://www.furaffinity.net/user/badmanners RedirectMatch 301 ^/@/gallery\b https://gallery.badmanners.xyz
Redirect 301 /@/gallery https://gallery.badmanners.xyz RedirectMatch 301 ^/@/(github|gh)\b https://github.com/BadMannersXYZ
Redirect 301 /@/github https://github.com/BadMannersXYZ RedirectMatch 301 ^/@/gitlab\b https://gitlab.com/Bad_Manners
Redirect 301 /@/gitlab https://gitlab.com/Bad_Manners RedirectMatch 301 ^/@/gumroad\b https://badmanners.gumroad.com/
Redirect 301 /@/inkbunny https://inkbunny.net/BadManners RedirectMatch 301 ^/@/(inkbunny|ib)\b https://inkbunny.net/BadManners
Redirect 301 /@/ib https://inkbunny.net/BadManners RedirectMatch 301 ^/@/itaku\b https://itaku.ee/profile/badmanners
Redirect 301 /@/itaku https://itaku.ee/profile/badmanners RedirectMatch 301 ^/@/itch\b https://bad-manners.itch.io
Redirect 301 /@/itch https://bad-manners.itch.io RedirectMatch 301 ^/@/keybase\b https://keybase.io/badmanners
Redirect 301 /@/keybase https://keybase.io/badmanners RedirectMatch 301 ^/@/ko[_-]?fi\b https://ko-fi.com/badmanners
Redirect 301 /@/mastodon https://meow.social/@BadManners RedirectMatch 301 ^/@/(mastodon|meow\.social|gulp\.cafe)\b https://meow.social/@BadManners
Redirect 301 /@/meow.social https://meow.social/@BadManners RedirectMatch 301 ^/@/neocities\b https://badmanners.neocities.org/
Redirect 301 /@/neocities https://badmanners.neocities.org/ RedirectMatch 301 ^/@/picarto\b https://www.picarto.tv/BadManners
Redirect 301 /@/picarto https://www.picarto.tv/BadManners RedirectMatch 301 ^/@/pillowfort\b https://www.pillowfort.social/BadManners
Redirect 301 /@/signal https://signal.me/#eu/ytt_rk0fFmAB2JAW-x2PbUiJyc_H3kYmfL_Pq4QNh5QIDsiFtjdFHaqFRs1D36tB RedirectMatch 301 ^/@/reddit\b https://www.reddit.com/user/BadManners_/
Redirect 301 /@/sf https://bad-manners.sofurry.com/ RedirectMatch 301 ^/@/signal\b https://signal.me/#eu/ytt_rk0fFmAB2JAW-x2PbUiJyc_H3kYmfL_Pq4QNh5QIDsiFtjdFHaqFRs1D36tB
Redirect 301 /@/sofurry https://bad-manners.sofurry.com/ RedirectMatch 301 ^/@/(sofurry|sf)\b https://bad-manners.sofurry.com/
Redirect 301 /@/steam https://steamcommunity.com/id/badmanners_/ RedirectMatch 301 ^/@/steam\b https://steamcommunity.com/id/badmanners_/
Redirect 301 /@/subscribestar https://subscribestar.adult/bad-manners RedirectMatch 301 ^/@/subscribestar\b https://subscribestar.adult/bad-manners
Redirect 301 /@/telegram https://t.me/bad_manners RedirectMatch 301 ^/@/(telegram|t\.me)\b https://t.me/bad_manners
Redirect 301 /@/t.me https://t.me/bad_manners RedirectMatch 301 ^/@/twitch\b https://www.twitch.tv/bad__manners
Redirect 301 /@/twitch https://www.twitch.tv/bad__manners RedirectMatch 301 ^/@/weasyl\b https://www.weasyl.com/~badmanners
Redirect 301 /@/weasyl https://www.weasyl.com/~badmanners RedirectMatch 301 ^/@/(x|twitter)\b https://x.com/BadManners__
Redirect 301 /@/x https://x.com/BadManners__ RedirectMatch 301 ^/@/(youtu\.?be|yt)\b https://www.youtube.com/@BadMannersXYZ
Redirect 301 /@/twitter https://x.com/BadManners__
`.trim(); `.trim();
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => {

View file

@ -9,13 +9,16 @@ import IconEkasPortal from "../components/icons/brands/IconEkasPortal.astro";
import IconFurAffinity from "../components/icons/brands/IconFurAffinity.astro"; import IconFurAffinity from "../components/icons/brands/IconFurAffinity.astro";
import IconGitHub from "../components/icons/brands/IconGitHub.astro"; import IconGitHub from "../components/icons/brands/IconGitHub.astro";
import IconGitLab from "../components/icons/brands/IconGitLab.astro"; import IconGitLab from "../components/icons/brands/IconGitLab.astro";
import IconGoogle from "../components/icons/brands/IconGoogle.astro";
import IconInkbunny from "../components/icons/brands/IconInkbunny.astro"; import IconInkbunny from "../components/icons/brands/IconInkbunny.astro";
import IconItaku from "../components/icons/brands/IconItaku.astro"; import IconItaku from "../components/icons/brands/IconItaku.astro";
import IconItchIO from "../components/icons/brands/IconItchIO.astro"; import IconItchIO from "../components/icons/brands/IconItchIO.astro";
import IconKeybase from "../components/icons/brands/IconKeybase.astro"; import IconKeybase from "../components/icons/brands/IconKeybase.astro";
import IconKofi from "../components/icons/brands/IconKofi.astro";
import IconMastodon from "../components/icons/brands/IconMastodon.astro"; import IconMastodon from "../components/icons/brands/IconMastodon.astro";
import IconNeocities from "../components/icons/brands/IconNeocities.astro"; import IconNeocities from "../components/icons/brands/IconNeocities.astro";
import IconPicarto from "../components/icons/brands/IconPicarto.astro"; 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 IconSignal from "../components/icons/brands/IconSignal.astro";
import IconSoFurry from "../components/icons/brands/IconSoFurry.astro"; import IconSoFurry from "../components/icons/brands/IconSoFurry.astro";
import IconSteam from "../components/icons/brands/IconSteam.astro"; import IconSteam from "../components/icons/brands/IconSteam.astro";
@ -24,6 +27,7 @@ import IconTelegram from "../components/icons/brands/IconTelegram.astro";
import IconTwitch from "../components/icons/brands/IconTwitch.astro"; import IconTwitch from "../components/icons/brands/IconTwitch.astro";
import IconWeasyl from "../components/icons/brands/IconWeasyl.astro"; import IconWeasyl from "../components/icons/brands/IconWeasyl.astro";
import IconX from "../components/icons/brands/IconX.astro"; import IconX from "../components/icons/brands/IconX.astro";
import IconYouTube from "../components/icons/brands/IconYouTube.astro";
--- ---
<BaseLayout> <BaseLayout>
@ -44,6 +48,13 @@ import IconX from "../components/icons/brands/IconX.astro";
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" 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, and a furry who occasionally writes stuff.</p>
{
Astro.site ? (
<a href={Astro.site} class="u-url sr-only" aria-label="Permalink">
{Astro.site}
</a>
) : null
}
<ul <ul
id="links" id="links"
class="grid grid-cols-3 gap-x-4 gap-y-5 px-4 pt-8 sm:grid-cols-4 sm:px-20 md:px-32" class="grid grid-cols-3 gap-x-4 gap-y-5 px-4 pt-8 sm:grid-cols-4 sm:px-20 md:px-32"
@ -62,7 +73,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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="p-category sr-only">E-mail address</p> <p class="sr-only">E-mail address</p>
</a> </a>
</li> </li>
<li id="bluesky"> <li id="bluesky">
@ -78,11 +89,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">@badmanners.xyz on Bluesky</p>
<span class="p-nickname">@badmanners.xyz</span>
on
<span class="p-category">Bluesky</span>
</p>
</a> </a>
</li> </li>
<li id="codeberg"> <li id="codeberg">
@ -98,11 +105,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadManners on Codeberg</p>
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Codeberg</span>
</p>
</a> </a>
</li> </li>
<li id="cohost"> <li id="cohost">
@ -118,11 +121,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadManners on Cohost</p>
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Cohost</span>
</p>
</a> </a>
</li> </li>
<li id="discord"> <li id="discord">
@ -137,11 +136,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">badmanners on Discord</p>
<span class="p-nickname">badmanners</span>
on
<span class="p-category">Discord</span>
</p>
</button> </button>
</li> </li>
<li id="eka-s-portal"> <li id="eka-s-portal">
@ -157,11 +152,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadManners on Eka's Portal</p>
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Eka's Portal</span>
</p>
</a> </a>
</li> </li>
<li id="fur-affinity"> <li id="fur-affinity">
@ -177,11 +168,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadManners on Fur Affinity</p>
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Fur Affinity</span>
</p>
</a> </a>
</li> </li>
<li id="github"> <li id="github">
@ -197,11 +184,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadMannersXYZ on GitHub</p>
<span class="p-nickname">BadMannersXYZ</span>
on
<span class="p-category">GitHub</span>
</p>
</a> </a>
</li> </li>
<li id="gitlab"> <li id="gitlab">
@ -217,11 +200,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">Bad_Manners on GitLab</p>
<span class="p-nickname">Bad_Manners</span> </a>
on </li>
<span class="p-category">GitLab</span> <li id="gmail">
</p> <a
class="u-email text-link group block w-full transition-colors motion-reduce:transition-none"
href="mailto:badmanners.vore@gmail.com"
target="_blank"
rel="me"
aria-label="badmanners.vore@gmail.com"
>
<IconGoogle
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"
/>
<p class="sr-only">Google/Gmail address</p>
</a> </a>
</li> </li>
<li id="inkbunny"> <li id="inkbunny">
@ -237,11 +232,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadManners on Inkbunny</p>
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Inkbunny</span>
</p>
</a> </a>
</li> </li>
<li id="itaku"> <li id="itaku">
@ -257,11 +248,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">badmanners on Itaku</p>
<span class="p-nickname">badmanners</span>
on
<span class="p-category">Itaku</span>
</p>
</a> </a>
</li> </li>
<li id="itch-io"> <li id="itch-io">
@ -277,11 +264,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">Bad Manners on Itch.io</p>
<span class="p-nickname">Bad Manners</span>
on
<span class="p-category">Itch.io</span>
</p>
</a> </a>
</li> </li>
<li id="keybase"> <li id="keybase">
@ -297,11 +280,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">badmanners on Keybase</p>
<span class="p-nickname">badmanners</span> </a>
on </li>
<span class="p-category">Keybase</span> <li id="ko-fi">
</p> <a
class="u-url text-link group block w-full transition-colors motion-reduce:transition-none"
href="https://ko-fi.com/badmanners"
target="_blank"
rel="me"
aria-label="Ko-fi"
>
<IconKofi
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"
/>
<p class="p-nickname sr-only">badmanners on Ko-fi</p>
</a> </a>
</li> </li>
<li id="mastodon"> <li id="mastodon">
@ -317,11 +312,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="sr-only">@BadManners p-nickname@meow.social on Mastodon</p>
<span class="p-nickname">@BadManners@meow.social</span>
on
<span class="p-category">Mastodon</span>
</p>
</a> </a>
</li> </li>
<li id="neocities"> <li id="neocities">
@ -337,11 +328,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="sr-only">badmanners p-nickname.neocities.org on Neocities</p>
<span class="p-nickname">badmanners.neocities.org</span>
on
<span class="p-category">Neocities</span>
</p>
</a> </a>
</li> </li>
<li id="picarto"> <li id="picarto">
@ -357,11 +344,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadManners on Picarto</p>
<span class="p-nickname">BadManners</span> </a>
on </li>
<span class="p-category">Picarto</span> <li id="reddit">
</p> <a
class="u-url text-link group block w-full transition-colors motion-reduce:transition-none"
href="https://www.reddit.com/user/BadManners_/"
target="_blank"
rel="me"
aria-label="Reddit"
>
<IconReddit
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"
/>
<p class="p-nickname sr-only">/u/BadManners_ on Reddit</p>
</a> </a>
</li> </li>
<li id="signal"> <li id="signal">
@ -377,11 +376,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">badmanners.10 on Signal</p>
<span class="p-nickname">badmanners.10</span>
on
<span class="p-category">Signal</span>
</p>
</a> </a>
</li> </li>
<li id="sofurry"> <li id="sofurry">
@ -397,11 +392,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">Bad Manners on SoFurry</p>
<span class="p-nickname">Bad Manners</span>
on
<span class="p-category">SoFurry</span>
</p>
</a> </a>
</li> </li>
<li id="steam"> <li id="steam">
@ -417,11 +408,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">badmanners_ on Steam</p>
<span class="p-nickname">badmanners_</span>
on
<span class="p-category">Steam</span>
</p>
</a> </a>
</li> </li>
<li id="subscribestar"> <li id="subscribestar">
@ -437,11 +424,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">Bad Manners on SubscribeStar</p>
<span class="p-nickname">Bad Manners</span>
on
<span class="p-category">SubscribeStar</span>
</p>
</a> </a>
</li> </li>
<li id="telegram"> <li id="telegram">
@ -457,11 +440,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">@bad_manners on Telegram</p>
<span class="p-nickname">@bad_manners</span>
on
<span class="p-category">Telegram</span>
</p>
</a> </a>
</li> </li>
<li id="twitch"> <li id="twitch">
@ -477,11 +456,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">bad__manners on Twitch</p>
<span class="p-nickname">bad__manners</span>
on
<span class="p-category">Twitch</span>
</p>
</a> </a>
</li> </li>
<li id="weasyl"> <li id="weasyl">
@ -497,11 +472,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">BadManners on Weasyl</p>
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Weasyl</span>
</p>
</a> </a>
</li> </li>
<li id="x"> <li id="x">
@ -517,11 +488,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="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" 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"> <p class="p-nickname sr-only">@BadManners__ on X</p>
<span class="p-nickname">@BadManners__</span> </a>
on </li>
<span class="p-category">X</span> <li id="youtube">
</p> <a
class="u-url text-link group block w-full transition-colors motion-reduce:transition-none"
href="https://www.youtube.com/@BadMannersXYZ"
target="_blank"
rel="me"
aria-label="YouTube"
>
<IconYouTube
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"
/>
<p class="p-nickname sr-only">@BadMannersXYZ on YouTube</p>
</a> </a>
</li> </li>
</ul> </ul>
@ -541,54 +524,61 @@ import IconX from "../components/icons/brands/IconX.astro";
if (!indexLinks) { if (!indexLinks) {
return; return;
} }
const emailAnchor = indexLinks.querySelector<HTMLElementTagNameMap["a"]>("#links li#e-mail a");
const usernameButtons = indexLinks.querySelectorAll<HTMLElementTagNameMap["button"]>( // Validate links
"#links li button[data-username]", const emailAnchors = indexLinks.querySelectorAll<HTMLElementTagNameMap["a"]>(`li > a[href^="mailto:"]`);
); const usernameButtons = indexLinks.querySelectorAll<HTMLElementTagNameMap["button"]>("li > button[data-username]");
if (!emailAnchor) { if (!emailAnchors.length) {
console.error("Missing e-mail anchor in #links list."); console.warn("Missing e-mail anchors in #links list.");
return;
} }
if (!usernameButtons.length) { if (!usernameButtons.length) {
console.error("Missing username buttons in #links list."); console.warn("Missing username buttons in #links list.");
return;
} }
indexLinks.querySelectorAll("li > :not(a, button)").forEach((el) => {
console.warn("Element with unknown type found in #links list:", el);
});
indexLinks.querySelectorAll("li > :is(a, button):not([aria-label])").forEach((el) => {
console.warn("Element with missing aria-label found in #links list:", el);
});
// Instantiate hover tooltips // Instantiate hover tooltips
tippy("#links li button, #links li a", { tippy("ul#links li > :is(a, button)[aria-label]", {
content: (el) => el.getAttribute("aria-label")!, content: (el) => el.getAttribute("aria-label")!,
theme: "bm", theme: "bm",
}); });
// Add clipboard copy logic + manual tooltips to e-mail anchor and username buttons // Add clipboard functionality to e-mail anchors and username buttons
let tooltipTimeoutTag: TimeoutTag = null; let tooltipTimeoutTag: TimeoutTag = null;
const emailTooltip = tippy(emailAnchor, { emailAnchors.forEach((anchor) => {
content: "E-mail address copied to clipboard!", if (!anchor.href.startsWith("mailto:")) {
trigger: "manual", console.warn("Missing mailto: href for e-mail anchor, ignoring...", anchor);
theme: "bm", return;
}); }
emailAnchor.addEventListener("click", (ev) => { const emailAddress = anchor.href.slice("mailto:".length);
ev.preventDefault(); const anchorTooltip = tippy(anchor, {
tooltipTimeoutTag && clearTimeout(tooltipTimeoutTag); content: "E-mail address copied to clipboard!",
hideAll(); trigger: "manual",
navigator.clipboard theme: "bm",
.writeText(emailAnchor.getAttribute("aria-label")!) });
.then(() => { anchor.addEventListener("click", (ev) => {
emailTooltip.setContent("E-mail address copied to clipboard!"); ev.preventDefault();
emailTooltip.show(); tooltipTimeoutTag && clearTimeout(tooltipTimeoutTag);
}) hideAll();
.catch((e) => { navigator.clipboard
console.error("Unable to copy e-mail address to clipboard.", e); .writeText(emailAddress)
emailTooltip.setContent("Unable to copy e-mail address!"); .then(() => {
emailTooltip.show(); anchorTooltip.setContent("E-mail address copied to clipboard!");
}); anchorTooltip.show();
})
.catch((e) => {
console.error("Unable to copy e-mail address to clipboard.", e);
anchorTooltip.setContent("Unable to copy e-mail address!");
anchorTooltip.show();
});
});
}); });
usernameButtons.forEach((button) => { usernameButtons.forEach((button) => {
const label = button.getAttribute("aria-label"); const label = button.getAttribute("aria-label");
if (!label) {
console.warn("Missing aria-label for button, ignoring...", button);
return;
}
const username = button.dataset.username; const username = button.dataset.username;
if (!username) { if (!username) {
console.warn("Missing data-username for button, ignoring...", button); console.warn("Missing data-username for button, ignoring...", button);
@ -596,7 +586,7 @@ import IconX from "../components/icons/brands/IconX.astro";
} }
button.removeAttribute("aria-disabled"); button.removeAttribute("aria-disabled");
button.removeAttribute("disabled"); button.removeAttribute("disabled");
const successContent = `${label} username copied to clipboard!`; const successContent = label ? `${label} username copied to clipboard!` : "Username copied to clipboard!";
const buttonTooltip = tippy(button, { const buttonTooltip = tippy(button, {
content: successContent, content: successContent,
trigger: "manual", trigger: "manual",
@ -613,8 +603,11 @@ import IconX from "../components/icons/brands/IconX.astro";
buttonTooltip.show(); buttonTooltip.show();
}) })
.catch((e) => { .catch((e) => {
console.error(`Unable to copy ${label} username to clipboard.`, e); console.error(
buttonTooltip.setContent(`Unable to copy ${label} username!`); label ? `Unable to copy ${label} username to clipboard.` : "Unable to copy username to clipboard.",
e,
);
buttonTooltip.setContent(label ? `Unable to copy ${label} username!` : "Unable to copy username!");
buttonTooltip.show(); buttonTooltip.show();
}); });
}); });