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 }; -};