diff --git a/api/db/migrations/20241015183037_matrix/migration.sql b/api/db/migrations/20241015183037_matrix/migration.sql new file mode 100644 index 0000000..a1f734c --- /dev/null +++ b/api/db/migrations/20241015183037_matrix/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "Handle" ADD VALUE 'matrix'; diff --git a/api/db/schema.prisma b/api/db/schema.prisma index f7bab9a..3f4b5e0 100644 --- a/api/db/schema.prisma +++ b/api/db/schema.prisma @@ -25,6 +25,7 @@ enum Handle { discord twitch linkedin + matrix github gitea forgejo diff --git a/api/src/graphql/socials.sdl.ts b/api/src/graphql/socials.sdl.ts index ab3491e..3e1be1b 100644 --- a/api/src/graphql/socials.sdl.ts +++ b/api/src/graphql/socials.sdl.ts @@ -17,6 +17,7 @@ export const schema = gql` discord twitch linkedin + matrix github gitea forgejo diff --git a/web/config/tailwind.config.js b/web/config/tailwind.config.js index bb50d75..6b7b749 100644 --- a/web/config/tailwind.config.js +++ b/web/config/tailwind.config.js @@ -6,6 +6,7 @@ import { SiTiktokHex, SiYoutubeHex, SiLinkedinHex, + SiMatrixHex, SiGithubHex, SiGiteaHex, SiLeetcodeHex, @@ -112,6 +113,10 @@ export const theme = { light: SiLinkedinHex, dark: SiLinkedinHex, }, + matrix: { + light: SiMatrixHex, + dark: invertColor(SiMatrixHex), + }, github: { light: SiGithubHex, dark: invertColor(SiGithubHex), diff --git a/web/src/components/Social/SocialForm/SocialForm.tsx b/web/src/components/Social/SocialForm/SocialForm.tsx index e764e93..67e716b 100644 --- a/web/src/components/Social/SocialForm/SocialForm.tsx +++ b/web/src/components/Social/SocialForm/SocialForm.tsx @@ -38,6 +38,7 @@ const types: FormSocial['type'][] = [ 'discord', 'twitch', 'linkedin', + 'matrix', 'github', 'gitea', 'forgejo', @@ -52,6 +53,15 @@ const types: FormSocial['type'][] = [ const urlHandles: FormSocial['type'][] = ['custom', 'gitea', 'forgejo'] const SocialForm = (props: SocialFormProps) => { + const emailRegex = + /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-]+)(\.[a-zA-Z]{2,5}){1,2}$/ + + const phoneRegex = /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/ + const urlRegex = + /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i + const matrixRegex = + /^([#@][a-zA-Z0-9_\-\.]+):([a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,})$/ + const [type, setType] = useState( props.social?.type ?? 'x' ) @@ -177,17 +187,20 @@ const SocialForm = (props: SocialFormProps) => { pattern: { value: type == 'email' - ? /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-]+)(\.[a-zA-Z]{2,5}){1,2}$/ + ? emailRegex : type == 'phone' - ? /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/ - : urlHandles.includes(type) && - /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i, + ? phoneRegex + : urlHandles.includes(type) + ? urlRegex + : type == 'matrix' && matrixRegex, message: `Invalid ${ urlHandles.includes(type) ? 'URL' : type == 'phone' - ? 'Phone Number' - : type == 'email' && 'Email' + ? 'phone number' + : type == 'email' + ? 'Email' + : type == 'matrix' && 'Matrix identifier' }`, }, }} diff --git a/web/src/lib/handle.tsx b/web/src/lib/handle.tsx index 8b8a60a..6ef2186 100644 --- a/web/src/lib/handle.tsx +++ b/web/src/lib/handle.tsx @@ -8,6 +8,7 @@ import { SiTiktok, SiYoutube, SiLinkedin, + SiMatrix, SiGithub, SiGitea, SiLeetcode, @@ -33,6 +34,7 @@ export const baseUrls: Record = { discord: 'https://discord.gg/', twitch: 'https://www.twitch.tv/', linkedin: 'https://www.linkedin.com/in/', + matrix: 'https://matrix.to/#/', github: 'https://github.com/', gitea: '', forgejo: '', @@ -61,6 +63,7 @@ const logoComponents: Record = { linkedin: ( ), + matrix: , github: , gitea: , forgejo: , @@ -80,6 +83,7 @@ export const sortOrder: Social['type'][] = [ 'phone', 'email', 'custom', + 'matrix', 'linkedin', 'leetcode', 'github',