diff --git a/package-lock.json b/package-lock.json
index 92e4523..85eb3c2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.0.1",
"dependencies": {
"@astrojs/check": "^0.9.4",
+ "@fujocoded/zod-transform-socials": "^0.0.11",
"@iconify-json/fa6-brands": "^1.2.5",
"@iconify-json/fa6-solid": "^1.1.20",
"@iconify-json/logos": "^1.1.42",
@@ -22,8 +23,7 @@
},
"devDependencies": {
"prettier": "^3.2.5",
- "prettier-plugin-astro": "^0.14.1",
- "social-links": "^1.14.0"
+ "prettier-plugin-astro": "^0.14.1"
},
"engines": {
"node": ">=20.0.0"
@@ -1008,6 +1008,16 @@
"node": ">=12"
}
},
+ "node_modules/@fujocoded/zod-transform-socials": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/@fujocoded/zod-transform-socials/-/zod-transform-socials-0.0.11.tgz",
+ "integrity": "sha512-Fydqs0wFHgwIb5IL9BVOAI6VN8Kaclla+mdGk8dYLbbyxg8msMCa+WnBQRIMS7VhZIDQnRqjIVfyy6KZ6Tz+Ug==",
+ "license": "MIT",
+ "dependencies": {
+ "social-links": "^1.14.0",
+ "zod": "^3.23.8"
+ }
+ },
"node_modules/@iconify-json/fa6-brands": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@iconify-json/fa6-brands/-/fa6-brands-1.2.5.tgz",
@@ -5716,8 +5726,7 @@
"node_modules/social-links": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/social-links/-/social-links-1.14.0.tgz",
- "integrity": "sha512-98FpRSrHilAcD/p4Aro2J5rzKnpFJ5QF5M9YEWns6gXwosgBqWKV+AtgYJFRIsvXMyd9UTD3SzPcSU8IJMW7cw==",
- "dev": true
+ "integrity": "sha512-98FpRSrHilAcD/p4Aro2J5rzKnpFJ5QF5M9YEWns6gXwosgBqWKV+AtgYJFRIsvXMyd9UTD3SzPcSU8IJMW7cw=="
},
"node_modules/source-map-js": {
"version": "1.2.1",
diff --git a/package.json b/package.json
index 6c50615..ee8086c 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"@astrojs/check": "^0.9.4",
+ "@fujocoded/zod-transform-socials": "^0.0.11",
"@iconify-json/fa6-brands": "^1.2.5",
"@iconify-json/fa6-solid": "^1.1.20",
"@iconify-json/logos": "^1.1.42",
@@ -24,8 +25,7 @@
},
"devDependencies": {
"prettier": "^3.2.5",
- "prettier-plugin-astro": "^0.14.1",
- "social-links": "^1.14.0"
+ "prettier-plugin-astro": "^0.14.1"
},
"engines": {
"node": ">=20.0.0"
diff --git a/src/components/TeamMemberCard.astro b/src/components/TeamMemberCard.astro
index 8cc0185..798c944 100644
--- a/src/components/TeamMemberCard.astro
+++ b/src/components/TeamMemberCard.astro
@@ -2,7 +2,7 @@
import type { ImageMetadata } from "astro";
import { Icon } from "astro-icon/components";
-import type { SocialsData } from "../lib/socials-transformer";
+import type { SocialLinksData } from "@fujocoded/zod-transform-socials";
import type { CollectionEntry } from "astro:content";
import type { Project } from "../content/config";
@@ -12,7 +12,7 @@ interface Props {
avatar: ImageMetadata;
roles: CollectionEntry<"team">["data"]["roles"];
project?: Project | undefined;
- contacts: SocialsData[];
+ contacts: SocialLinksData[];
}
const props = Astro.props;
@@ -39,7 +39,6 @@ const props = Astro.props;
) : (
Object.keys(props.roles).map(
- // @ts-expect-error
(project: Project) =>
!!props.roles[project].length && (
@@ -64,19 +63,22 @@ const props = Astro.props;
diff --git a/src/content/config.ts b/src/content/config.ts
index 35fcbf6..8de7835 100644
--- a/src/content/config.ts
+++ b/src/content/config.ts
@@ -1,9 +1,6 @@
import { defineCollection, z } from "astro:content";
-import {
- socialsSchema,
- transformSocial,
- type SocialsData,
-} from "../lib/socials-transformer";
+
+import { SocialLinks } from "@fujocoded/zod-transform-socials";
const Volume0Issue1Role = z.enum([
"Technical Writer",
@@ -44,12 +41,7 @@ const teamCollection = defineCollection({
name: z.string(),
avatar: tools.image(),
roles,
- contacts: socialsSchema
- .array()
- .default([])
- .transform(
- (contacts) => contacts.map(transformSocial) as Array
- ),
+ contacts: SocialLinks,
}),
});
diff --git a/src/content/team/enigmalea.yaml b/src/content/team/enigmalea.yaml
index fb73c5e..7769ce7 100644
--- a/src/content/team/enigmalea.yaml
+++ b/src/content/team/enigmalea.yaml
@@ -21,12 +21,7 @@ roles:
- Copy Writer
contacts:
- https://enigmalea.quest
- - https://enigmalea.tumblr.com
- - https://enigmalea.bsky.social
- - url: https://easymode.im/@enigmalea
- platform: firefish
- username: enigmalea
+ - url: https://bsky.app/profile/enigmalea.quest
+ icon: simple-icons:bluesky
- https://archiveofourown.org/users/enigmalea
- - https://github.com/enigmalea
- - https://enigmalea.dreamwidth.org
- - https://ko-fi.com/enigmalea
+ - https://enigmalea.tumblr.com
diff --git a/src/content/team/ria.yaml b/src/content/team/ria.yaml
index d6247b0..5f8792f 100644
--- a/src/content/team/ria.yaml
+++ b/src/content/team/ria.yaml
@@ -7,3 +7,4 @@ roles:
- Additional Coding
contacts:
- https://github.com/riazaia
+ - https://bsky.app/profile/riazaia.bsky.social
diff --git a/src/content/team/yuu.yaml b/src/content/team/yuu.yaml
index b9ca08f..3ec62ce 100644
--- a/src/content/team/yuu.yaml
+++ b/src/content/team/yuu.yaml
@@ -8,4 +8,4 @@ roles:
- Beta Reader
- Proofreader
contacts:
- - https://where.yuu.gay/
+ - https://where.yuu.observer/
diff --git a/src/lib/socials-transformer.ts b/src/lib/socials-transformer.ts
deleted file mode 100644
index 4d48101..0000000
--- a/src/lib/socials-transformer.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-import { z } from "astro:content";
-import { type ProfileMatch, SocialLinks } from "social-links";
-
-export const socialsSchema = z.union([
- z.string().url(),
- z.object({
- icon: z.string().optional(),
- platform: z.string().optional(),
- url: z.string().url(),
- username: z.string().optional(),
- }),
-]);
-export type SocialsSchema = z.infer;
-
-export type SocialsData = {
- icon: string | null;
- url: string;
- username: string | null;
- platform: WEBSITE_TYPES;
-};
-
-export type WEBSITE_TYPES =
- | "github"
- | "tumblr"
- | "twitter"
- | "npm"
- | "web"
- | "bsky"
- | "twitch"
- | "mastodon"
- | "dreamwidth"
- | "ko-fi"
- | "patreon"
- | "youtube"
- | "kickstarter"
- | "inprnt"
- | "neocities";
-
-export const transformSocial = (social: SocialsSchema) => {
- if (typeof social == "string") {
- return extractSocialData({ url: social });
- }
- const { icon, url, platform, username } = social;
- const data = extractSocialData({ url });
-
- return {
- ...data,
- icon:
- icon ??
- (platform === undefined
- ? data.icon
- : getSocialIcon(platform as WEBSITE_TYPES)),
- url,
- platform,
- username,
- };
-};
-
-const socialLinks = new SocialLinks();
-const tumblrMatches: ProfileMatch[] = [
- {
- match: "https?://([a-z0-9-]+).tumblr.com/?",
- // TODO: more may be necessary for things like extracting usernames
- group: 1,
- },
- {
- match: "https?://www.tumblr.com/([a-z0-9-]+)",
- // TODO: more may be necessary for things like extracting usernames
- group: 1,
- },
-];
-socialLinks.addProfile("tumblr", tumblrMatches);
-const kofiMatches: ProfileMatch[] = [
- {
- match: "https?://ko-fi.com/([a-z0-9-_]+)",
- group: 1,
- },
-];
-socialLinks.addProfile("ko-fi", kofiMatches);
-
-const inprntMatches: ProfileMatch[] = [
- {
- match: "https?://(?:www.)?inprnt.com/gallery/([a-z0-9-]+)/?",
- group: 1,
- },
-];
-socialLinks.addProfile("inprnt", inprntMatches);
-
-const neocitiesMatches: ProfileMatch[] = [
- {
- match: "https?://([a-z0-9-]+).neocities.org",
- group: 1,
- },
-];
-socialLinks.addProfile("neocities", neocitiesMatches);
-
-const blueSkyMatches: ProfileMatch[] = [
- {
- match: "https?://([a-z0-9-]+).bsky.social",
- group: 1,
- },
-];
-socialLinks.addProfile("bsky", blueSkyMatches);
-
-const ao3Matches: ProfileMatch[] = [
- {
- match: "https?://archiveofourown.org/users/([a-z0-9-]+)",
- group: 1,
- },
-];
-socialLinks.addProfile("archiveofourown", ao3Matches);
-
-const dreamwidthMatches: ProfileMatch[] = [
- {
- match: "https?://([a-z0-9-]+).dreamwidth.org",
- group: 1,
- },
-];
-socialLinks.addProfile("dreamwidth", dreamwidthMatches);
-
-const furaffinityMatches: ProfileMatch[] = [
- {
- match: "https?://www.furaffinity.net/user/([a-z0-9-]+)",
- group: 1,
- },
-];
-socialLinks.addProfile("furaffinity", furaffinityMatches);
-
-const carrdMatches: ProfileMatch[] = [
- {
- match: "https?://([a-z0-9-]+).carrd.co/?",
- group: 1,
- },
-];
-socialLinks.addProfile("carrd", carrdMatches);
-
-const getSocialIcon = (platform: WEBSITE_TYPES) => {
- if (platform === "inprnt") {
- return "lucide:shopping-bag";
- }
- if (platform === "neocities") {
- return "lucide:cat";
- }
- if (platform === "bsky") {
- return "simple-icons:bluesky";
- }
- if (platform === "dreamwidth") {
- return "simple-icons:livejournal";
- }
- return "simple-icons:" + platform.replaceAll("-", "");
-};
-
-export const extractSocialData = ({ url }: { url: string }): SocialsData => {
- const lowerUrl = url.toLowerCase();
- const socialLinkAttempt = socialLinks.detectProfile(lowerUrl);
- if (socialLinkAttempt) {
- return {
- url,
- platform: socialLinkAttempt as WEBSITE_TYPES,
- username: socialLinks.getProfileId(socialLinkAttempt, lowerUrl),
- icon: getSocialIcon(socialLinkAttempt as WEBSITE_TYPES),
- };
- }
- // If you cannot find it, return the original url
- return { url, platform: "web", username: null, icon: null };
-};