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",
"version": "2.1.0",
"version": "2.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "badmanners.xyz",
"version": "2.1.0",
"version": "2.1.1",
"hasInstallScript": true,
"dependencies": {
"@astrojs/check": "^0.9.2",

View file

@ -1,7 +1,7 @@
{
"name": "badmanners.xyz",
"type": "module",
"version": "2.1.0",
"version": "2.1.1",
"scripts": {
"postinstall": "astro sync",
"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 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.

View file

@ -56,8 +56,12 @@ import IconTriangleExclamation from "./icons/IconTriangleExclamation.astro";
import { ENABLE_VIEW_TRANSITIONS } from "astro:env/client";
const ageRestrictedModalSetup = () => {
if (localStorage.ageVerified !== "true") {
const modal = document.querySelector<HTMLElementTagNameMap["div"]>("div#modal-age-restricted")!;
const modal = document.querySelector<HTMLElementTagNameMap["div"]>("body > 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 onRejectButtonClick = (e: MouseEvent) => {
e.preventDefault();
@ -69,7 +73,8 @@ import IconTriangleExclamation from "./icons/IconTriangleExclamation.astro";
(e: MouseEvent) => {
e.preventDefault();
rejectButton.removeEventListener("click", onRejectButtonClick);
localStorage.ageVerified = "true";
ageVerified = "true";
localStorage.ageVerified = ageVerified;
document.body.style.overflow = "auto";
document.querySelectorAll("body > :not(#modal-age-restricted)").forEach((el) => el.removeAttribute("inert"));
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>
import { ENABLE_VIEW_TRANSITIONS } from "astro:env/client";
type ColorScheme = "auto" | "dark" | "light";
const colorSchemeSetup = () => {
let colorScheme = localStorage.colorScheme;
let colorScheme: ColorScheme | undefined = localStorage.colorScheme;
if (!colorScheme || colorScheme === "auto") {
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) => {
button.classList.remove("hidden");
button.style.removeProperty("display");
button.setAttribute("aria-hidden", "false");
button.addEventListener("click", (e) => {
e.preventDefault();
if (colorScheme === "dark") {
colorScheme = "light";
document.body.classList.remove("dark");
} else {
colorScheme = "dark";
document.body.classList.add("dark");
}
localStorage.colorScheme = colorScheme;
});
button.addEventListener("click", toggleColorScheme);
});
};
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
RedirectMatch 301 ^/tos(\/(index.html)?)?$ /terms_of_service/
RedirectMatch 301 ^/contact(\/(index.html)?)?$ /
Redirect 301 /@/aryion https://aryion.com/g4/user/BadManners
Redirect 301 /@/eka https://aryion.com/g4/user/BadManners
Redirect 301 /@/bluesky https://bsky.app/profile/badmanners.xyz
Redirect 301 /@/bsky https://bsky.app/profile/badmanners.xyz
Redirect 301 /@/codeberg https://codeberg.org/BadManners
Redirect 301 /@/cohost https://cohost.org/BadManners
Redirect 301 /@/fa https://www.furaffinity.net/user/badmanners
Redirect 301 /@/furaffinity https://www.furaffinity.net/user/badmanners
Redirect 301 /@/gallery https://gallery.badmanners.xyz
Redirect 301 /@/github https://github.com/BadMannersXYZ
Redirect 301 /@/gitlab https://gitlab.com/Bad_Manners
Redirect 301 /@/inkbunny https://inkbunny.net/BadManners
Redirect 301 /@/ib https://inkbunny.net/BadManners
Redirect 301 /@/itaku https://itaku.ee/profile/badmanners
Redirect 301 /@/itch https://bad-manners.itch.io
Redirect 301 /@/keybase https://keybase.io/badmanners
Redirect 301 /@/mastodon https://meow.social/@BadManners
Redirect 301 /@/meow.social https://meow.social/@BadManners
Redirect 301 /@/neocities https://badmanners.neocities.org/
Redirect 301 /@/picarto https://www.picarto.tv/BadManners
Redirect 301 /@/signal https://signal.me/#eu/ytt_rk0fFmAB2JAW-x2PbUiJyc_H3kYmfL_Pq4QNh5QIDsiFtjdFHaqFRs1D36tB
Redirect 301 /@/sf https://bad-manners.sofurry.com/
Redirect 301 /@/sofurry https://bad-manners.sofurry.com/
Redirect 301 /@/steam https://steamcommunity.com/id/badmanners_/
Redirect 301 /@/subscribestar https://subscribestar.adult/bad-manners
Redirect 301 /@/telegram https://t.me/bad_manners
Redirect 301 /@/t.me https://t.me/bad_manners
Redirect 301 /@/twitch https://www.twitch.tv/bad__manners
Redirect 301 /@/weasyl https://www.weasyl.com/~badmanners
Redirect 301 /@/x https://x.com/BadManners__
Redirect 301 /@/twitter https://x.com/BadManners__
RedirectMatch 301 ^/@/(aryion|ekas?)\b https://aryion.com/g4/user/BadManners
RedirectMatch 301 ^/@/(bluesky|bsky)\b https://bsky.app/profile/badmanners.xyz
RedirectMatch 301 ^/@/(buymeacoffee|bmac)\b https://www.buymeacoffee.com/BadMannersXYZ
RedirectMatch 301 ^/@/carrd\b https://badmanners.carrd.co
RedirectMatch 301 ^/@/codeberg\b https://codeberg.org/BadManners
RedirectMatch 301 ^/@/cohost\b https://cohost.org/BadManners
RedirectMatch 301 ^/@/(fur[_-]?affinity|fa)\b https://www.furaffinity.net/user/badmanners
RedirectMatch 301 ^/@/gallery\b https://gallery.badmanners.xyz
RedirectMatch 301 ^/@/(github|gh)\b https://github.com/BadMannersXYZ
RedirectMatch 301 ^/@/gitlab\b https://gitlab.com/Bad_Manners
RedirectMatch 301 ^/@/gumroad\b https://badmanners.gumroad.com/
RedirectMatch 301 ^/@/(inkbunny|ib)\b https://inkbunny.net/BadManners
RedirectMatch 301 ^/@/itaku\b https://itaku.ee/profile/badmanners
RedirectMatch 301 ^/@/itch\b https://bad-manners.itch.io
RedirectMatch 301 ^/@/keybase\b https://keybase.io/badmanners
RedirectMatch 301 ^/@/ko[_-]?fi\b https://ko-fi.com/badmanners
RedirectMatch 301 ^/@/(mastodon|meow\.social|gulp\.cafe)\b https://meow.social/@BadManners
RedirectMatch 301 ^/@/neocities\b https://badmanners.neocities.org/
RedirectMatch 301 ^/@/picarto\b https://www.picarto.tv/BadManners
RedirectMatch 301 ^/@/pillowfort\b https://www.pillowfort.social/BadManners
RedirectMatch 301 ^/@/reddit\b https://www.reddit.com/user/BadManners_/
RedirectMatch 301 ^/@/signal\b https://signal.me/#eu/ytt_rk0fFmAB2JAW-x2PbUiJyc_H3kYmfL_Pq4QNh5QIDsiFtjdFHaqFRs1D36tB
RedirectMatch 301 ^/@/(sofurry|sf)\b https://bad-manners.sofurry.com/
RedirectMatch 301 ^/@/steam\b https://steamcommunity.com/id/badmanners_/
RedirectMatch 301 ^/@/subscribestar\b https://subscribestar.adult/bad-manners
RedirectMatch 301 ^/@/(telegram|t\.me)\b https://t.me/bad_manners
RedirectMatch 301 ^/@/twitch\b https://www.twitch.tv/bad__manners
RedirectMatch 301 ^/@/weasyl\b https://www.weasyl.com/~badmanners
RedirectMatch 301 ^/@/(x|twitter)\b https://x.com/BadManners__
RedirectMatch 301 ^/@/(youtu\.?be|yt)\b https://www.youtube.com/@BadMannersXYZ
`.trim();
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 IconGitHub from "../components/icons/brands/IconGitHub.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 IconItaku from "../components/icons/brands/IconItaku.astro";
import IconItchIO from "../components/icons/brands/IconItchIO.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 IconNeocities from "../components/icons/brands/IconNeocities.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 IconSoFurry from "../components/icons/brands/IconSoFurry.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 IconWeasyl from "../components/icons/brands/IconWeasyl.astro";
import IconX from "../components/icons/brands/IconX.astro";
import IconYouTube from "../components/icons/brands/IconYouTube.astro";
---
<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"
/>
<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
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"
@ -62,7 +73,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-category sr-only">E-mail address</p>
<p class="sr-only">E-mail address</p>
</a>
</li>
<li id="bluesky">
@ -78,11 +89,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">@badmanners.xyz</span>
on
<span class="p-category">Bluesky</span>
</p>
<p class="p-nickname sr-only">@badmanners.xyz on Bluesky</p>
</a>
</li>
<li id="codeberg">
@ -98,11 +105,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Codeberg</span>
</p>
<p class="p-nickname sr-only">BadManners on Codeberg</p>
</a>
</li>
<li id="cohost">
@ -118,11 +121,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Cohost</span>
</p>
<p class="p-nickname sr-only">BadManners on Cohost</p>
</a>
</li>
<li id="discord">
@ -137,11 +136,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">badmanners</span>
on
<span class="p-category">Discord</span>
</p>
<p class="p-nickname sr-only">badmanners on Discord</p>
</button>
</li>
<li id="eka-s-portal">
@ -157,11 +152,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Eka's Portal</span>
</p>
<p class="p-nickname sr-only">BadManners on Eka's Portal</p>
</a>
</li>
<li id="fur-affinity">
@ -177,11 +168,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Fur Affinity</span>
</p>
<p class="p-nickname sr-only">BadManners on Fur Affinity</p>
</a>
</li>
<li id="github">
@ -197,11 +184,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadMannersXYZ</span>
on
<span class="p-category">GitHub</span>
</p>
<p class="p-nickname sr-only">BadMannersXYZ on GitHub</p>
</a>
</li>
<li id="gitlab">
@ -217,11 +200,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">Bad_Manners</span>
on
<span class="p-category">GitLab</span>
</p>
<p class="p-nickname sr-only">Bad_Manners on GitLab</p>
</a>
</li>
<li id="gmail">
<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>
</li>
<li id="inkbunny">
@ -237,11 +232,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Inkbunny</span>
</p>
<p class="p-nickname sr-only">BadManners on Inkbunny</p>
</a>
</li>
<li id="itaku">
@ -257,11 +248,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">badmanners</span>
on
<span class="p-category">Itaku</span>
</p>
<p class="p-nickname sr-only">badmanners on Itaku</p>
</a>
</li>
<li id="itch-io">
@ -277,11 +264,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">Bad Manners</span>
on
<span class="p-category">Itch.io</span>
</p>
<p class="p-nickname sr-only">Bad Manners on Itch.io</p>
</a>
</li>
<li id="keybase">
@ -297,11 +280,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">badmanners</span>
on
<span class="p-category">Keybase</span>
</p>
<p class="p-nickname sr-only">badmanners on Keybase</p>
</a>
</li>
<li id="ko-fi">
<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>
</li>
<li id="mastodon">
@ -317,11 +312,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">@BadManners@meow.social</span>
on
<span class="p-category">Mastodon</span>
</p>
<p class="sr-only">@BadManners p-nickname@meow.social on Mastodon</p>
</a>
</li>
<li id="neocities">
@ -337,11 +328,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">badmanners.neocities.org</span>
on
<span class="p-category">Neocities</span>
</p>
<p class="sr-only">badmanners p-nickname.neocities.org on Neocities</p>
</a>
</li>
<li id="picarto">
@ -357,11 +344,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Picarto</span>
</p>
<p class="p-nickname sr-only">BadManners on Picarto</p>
</a>
</li>
<li id="reddit">
<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>
</li>
<li id="signal">
@ -377,11 +376,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">badmanners.10</span>
on
<span class="p-category">Signal</span>
</p>
<p class="p-nickname sr-only">badmanners.10 on Signal</p>
</a>
</li>
<li id="sofurry">
@ -397,11 +392,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">Bad Manners</span>
on
<span class="p-category">SoFurry</span>
</p>
<p class="p-nickname sr-only">Bad Manners on SoFurry</p>
</a>
</li>
<li id="steam">
@ -417,11 +408,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">badmanners_</span>
on
<span class="p-category">Steam</span>
</p>
<p class="p-nickname sr-only">badmanners_ on Steam</p>
</a>
</li>
<li id="subscribestar">
@ -437,11 +424,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">Bad Manners</span>
on
<span class="p-category">SubscribeStar</span>
</p>
<p class="p-nickname sr-only">Bad Manners on SubscribeStar</p>
</a>
</li>
<li id="telegram">
@ -457,11 +440,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">@bad_manners</span>
on
<span class="p-category">Telegram</span>
</p>
<p class="p-nickname sr-only">@bad_manners on Telegram</p>
</a>
</li>
<li id="twitch">
@ -477,11 +456,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">bad__manners</span>
on
<span class="p-category">Twitch</span>
</p>
<p class="p-nickname sr-only">bad__manners on Twitch</p>
</a>
</li>
<li id="weasyl">
@ -497,11 +472,7 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">BadManners</span>
on
<span class="p-category">Weasyl</span>
</p>
<p class="p-nickname sr-only">BadManners on Weasyl</p>
</a>
</li>
<li id="x">
@ -517,11 +488,23 @@ import IconX from "../components/icons/brands/IconX.astro";
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">
<span class="p-nickname">@BadManners__</span>
on
<span class="p-category">X</span>
</p>
<p class="p-nickname sr-only">@BadManners__ on X</p>
</a>
</li>
<li id="youtube">
<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>
</li>
</ul>
@ -541,54 +524,61 @@ import IconX from "../components/icons/brands/IconX.astro";
if (!indexLinks) {
return;
}
const emailAnchor = indexLinks.querySelector<HTMLElementTagNameMap["a"]>("#links li#e-mail a");
const usernameButtons = indexLinks.querySelectorAll<HTMLElementTagNameMap["button"]>(
"#links li button[data-username]",
);
if (!emailAnchor) {
console.error("Missing e-mail anchor in #links list.");
return;
// Validate links
const emailAnchors = indexLinks.querySelectorAll<HTMLElementTagNameMap["a"]>(`li > a[href^="mailto:"]`);
const usernameButtons = indexLinks.querySelectorAll<HTMLElementTagNameMap["button"]>("li > button[data-username]");
if (!emailAnchors.length) {
console.warn("Missing e-mail anchors in #links list.");
}
if (!usernameButtons.length) {
console.error("Missing username buttons in #links list.");
return;
console.warn("Missing username buttons in #links list.");
}
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
tippy("#links li button, #links li a", {
tippy("ul#links li > :is(a, button)[aria-label]", {
content: (el) => el.getAttribute("aria-label")!,
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;
const emailTooltip = tippy(emailAnchor, {
content: "E-mail address copied to clipboard!",
trigger: "manual",
theme: "bm",
});
emailAnchor.addEventListener("click", (ev) => {
ev.preventDefault();
tooltipTimeoutTag && clearTimeout(tooltipTimeoutTag);
hideAll();
navigator.clipboard
.writeText(emailAnchor.getAttribute("aria-label")!)
.then(() => {
emailTooltip.setContent("E-mail address copied to clipboard!");
emailTooltip.show();
})
.catch((e) => {
console.error("Unable to copy e-mail address to clipboard.", e);
emailTooltip.setContent("Unable to copy e-mail address!");
emailTooltip.show();
});
emailAnchors.forEach((anchor) => {
if (!anchor.href.startsWith("mailto:")) {
console.warn("Missing mailto: href for e-mail anchor, ignoring...", anchor);
return;
}
const emailAddress = anchor.href.slice("mailto:".length);
const anchorTooltip = tippy(anchor, {
content: "E-mail address copied to clipboard!",
trigger: "manual",
theme: "bm",
});
anchor.addEventListener("click", (ev) => {
ev.preventDefault();
tooltipTimeoutTag && clearTimeout(tooltipTimeoutTag);
hideAll();
navigator.clipboard
.writeText(emailAddress)
.then(() => {
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) => {
const label = button.getAttribute("aria-label");
if (!label) {
console.warn("Missing aria-label for button, ignoring...", button);
return;
}
const username = button.dataset.username;
if (!username) {
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("disabled");
const successContent = `${label} username copied to clipboard!`;
const successContent = label ? `${label} username copied to clipboard!` : "Username copied to clipboard!";
const buttonTooltip = tippy(button, {
content: successContent,
trigger: "manual",
@ -613,8 +603,11 @@ import IconX from "../components/icons/brands/IconX.astro";
buttonTooltip.show();
})
.catch((e) => {
console.error(`Unable to copy ${label} username to clipboard.`, e);
buttonTooltip.setContent(`Unable to copy ${label} username!`);
console.error(
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();
});
});