This commit is contained in:
j23saw
2020-10-07 18:18:53 +05:30
24 changed files with 7910 additions and 422 deletions
+64
View File
@@ -14,6 +14,15 @@
"code" "code"
] ]
}, },
{
"login": "Hardik0307",
"name": "Hardik Bagada",
"avatar_url": "https://avatars3.githubusercontent.com/u/41434099?v=4",
"profile": "https://github.com/Hardik0307",
"contributions": [
"code"
]
},
{ {
"login": "antonkomarev", "login": "antonkomarev",
"name": "Anton Komarev", "name": "Anton Komarev",
@@ -22,6 +31,61 @@
"contributions": [ "contributions": [
"plugin" "plugin"
] ]
},
{
"login": "KKVANONYMOUS",
"name": "Kunal Kumar Verma",
"avatar_url": "https://avatars3.githubusercontent.com/u/58628586?v=4",
"profile": "https://kkvanonymous.github.io/",
"contributions": [
"code"
]
},
{
"login": "jaideepghosh",
"name": "Jaideep Ghosh",
"avatar_url": "https://avatars2.githubusercontent.com/u/3909648?v=4",
"profile": "http://jaideepghosh.blogspot.com",
"contributions": [
"code"
]
}
{
"login": "YashKandalkar",
"name": "yash",
"avatar_url": "https://avatars0.githubusercontent.com/u/35102959?v=4",
"profile": "http://yashkandalkar.github.io",
"contributions": [
"code"
]
},
{
"login": "abhijit-hota",
"name": "Abhijit Hota",
"avatar_url": "https://avatars0.githubusercontent.com/u/8116174?v=4",
"profile": "https://github.com/abhijit-hota",
"contributions": [
"code",
"test"
]
},
{
"login": "Maddoxx88",
"name": "Sunit Shirke",
"avatar_url": "https://avatars1.githubusercontent.com/u/34238672?v=4",
"profile": "https://maddoxx88.github.io/",
"contributions": [
"code"
]
}
{
"login": "g-savitha",
"name": "Savitha Gollamudi",
"avatar_url": "https://avatars0.githubusercontent.com/u/31612459?v=4",
"profile": "https://www.gsavitha.in",
"contributions": [
"code"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,
+43
View File
@@ -0,0 +1,43 @@
<!--
For Work In Progress Pull Requests, please use the Draft PR feature,
see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
For a timely review/response, please avoid force-pushing additional
commits if your PR already received reviews or comments.
Before submitting a Pull Request, please ensure you've done the following:
- 📖 Read the Contributing Guide: https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/CONTRIBUTING.md#create-a-pull-request.
- 📖 Read the Code of Conduct: https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/CODE_OF_CONDUCT.md.
- 👷‍♀️ Create small PRs. In most cases this will be possible.
- ✅ Provide issue number with link.
- 📝 Use descriptive commit messages.
- 📗 Update any related documentation and include any relevant screenshots.
-->
## What type of PR is this? (check all applicable)
- [ ] Refactor
- [ ] Feature
- [ ] Bug Fix
- [ ] Enhancement
- [ ] Documentation Update
## Description
## Related Tickets & Documents
## QA Instructions, Screenshots, Recordings
_Please replace this line with instructions on how to test your changes, as well
as any relevant images for UI changes._
<!-- ## Added tests?
- [ ] yes
- [ ] no, because they aren't needed
- [ ] no, because I need help -->
## Added to documentation?
- [ ] readme
+8 -1
View File
@@ -157,7 +157,7 @@ Please read [`CONTRIBUTING`](CONTRIBUTING.md) for details on our [`CODE OF CONDU
## Contributors ✨ ## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-) [![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END --> <!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -167,7 +167,14 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<table> <table>
<tr> <tr>
<td align="center"><a href="https://github.com/sarbikbetal"><img src="https://avatars2.githubusercontent.com/u/41508422?v=4" width="100px;" alt=""/><br /><sub><b>Sarbik Betal</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=sarbikbetal" title="Code">💻</a></td> <td align="center"><a href="https://github.com/sarbikbetal"><img src="https://avatars2.githubusercontent.com/u/41508422?v=4" width="100px;" alt=""/><br /><sub><b>Sarbik Betal</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=sarbikbetal" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Hardik0307"><img src="https://avatars3.githubusercontent.com/u/41434099?v=4" width="100px;" alt=""/><br /><sub><b>Hardik Bagada</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=Hardik0307" title="Code">💻</a></td>
<td align="center"><a href="https://komarev.com"><img src="https://avatars0.githubusercontent.com/u/1849174?v=4" width="100px;" alt=""/><br /><sub><b>Anton Komarev</b></sub></a><br /><a href="#plugin-antonkomarev" title="Plugin/utility libraries">🔌</a></td> <td align="center"><a href="https://komarev.com"><img src="https://avatars0.githubusercontent.com/u/1849174?v=4" width="100px;" alt=""/><br /><sub><b>Anton Komarev</b></sub></a><br /><a href="#plugin-antonkomarev" title="Plugin/utility libraries">🔌</a></td>
<td align="center"><a href="https://kkvanonymous.github.io/"><img src="https://avatars3.githubusercontent.com/u/58628586?v=4" width="100px;" alt=""/><br /><sub><b>Kunal Kumar Verma</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=KKVANONYMOUS" title="Code">💻</a></td>
<td align="center"><a href="http://jaideepghosh.blogspot.com"><img src="https://avatars2.githubusercontent.com/u/3909648?v=4" width="100px;" alt=""/><br /><sub><b>Jaideep Ghosh</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=jaideepghosh" title="Code">💻</a></td>
<td align="center"><a href="http://yashkandalkar.github.io"><img src="https://avatars0.githubusercontent.com/u/35102959?v=4" width="100px;" alt=""/><br /><sub><b>yash</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=YashKandalkar" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/abhijit-hota"><img src="https://avatars0.githubusercontent.com/u/8116174?v=4" width="100px;" alt=""/><br /><sub><b>Abhijit Hota</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=abhijit-hota" title="Code">💻</a> <a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=abhijit-hota" title="Tests">⚠️</a></td>
<td align="center"><a href="https://maddoxx88.github.io/"><img src="https://avatars1.githubusercontent.com/u/34238672?v=4" width="100px;" alt=""/><br /><sub><b>Sunit Shirke</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=Maddoxx88" title="Code">💻</a></td>
<td align="center"><a href="https://www.gsavitha.in"><img src="https://avatars0.githubusercontent.com/u/31612459?v=4" width="100px;" alt=""/><br /><sub><b>Savitha Gollamudi</b></sub></a><br /><a href="https://github.com/rahuldkjain/github-profile-readme-generator/commits?author=g-savitha" title="Code">💻</a></td>
</tr> </tr>
</table> </table>
+1
View File
@@ -0,0 +1 @@
module.exports = "test-file-stub"
+27
View File
@@ -0,0 +1,27 @@
const React = require("react")
const gatsby = jest.requireActual("gatsby")
module.exports = {
...gatsby,
graphql: jest.fn(),
Link: jest.fn().mockImplementation(
// these props are invalid for an `a` tag
({
activeClassName,
activeStyle,
getProps,
innerRef,
partiallyActive,
ref,
replace,
to,
...rest
}) =>
React.createElement("a", {
...rest,
href: to,
})
),
StaticQuery: jest.fn(),
useStaticQuery: jest.fn(),
}
+5
View File
@@ -0,0 +1,5 @@
const babelOptions = {
presets: ["babel-preset-gatsby"],
}
module.exports = require("babel-jest").createTransformer(babelOptions)
+15
View File
@@ -0,0 +1,15 @@
module.exports = {
transform: {
"^.+\\.jsx?$": `<rootDir>/jest-preprocess.js`,
},
moduleNameMapper: {
".+\\.(css|styl|less|sass|scss)$": `identity-obj-proxy`,
".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": `<rootDir>/__mocks__/file-mock.js`,
},
testPathIgnorePatterns: [`node_modules`, `\\.cache`, `<rootDir>.*/public`],
transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`],
globals: {
__PATH_PREFIX__: ``,
},
setupFiles: [`<rootDir>/loadershim.js`],
}
+3
View File
@@ -0,0 +1,3 @@
global.___loader = {
enqueue: jest.fn(),
}
+7384 -366
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -25,12 +25,17 @@
"react-helmet": "^6.1.0" "react-helmet": "^6.1.0"
}, },
"devDependencies": { "devDependencies": {
"babel-jest": "26.3.0",
"babel-preset-gatsby": "0.5.11",
"gatsby-plugin-postcss": "^2.3.11", "gatsby-plugin-postcss": "^2.3.11",
"gatsby-plugin-purgecss": "^5.0.0", "gatsby-plugin-purgecss": "^5.0.0",
"gatsby-plugin-twitter": "^2.3.10", "gatsby-plugin-twitter": "^2.3.10",
"gatsby-remark-embedder": "^3.0.0", "gatsby-remark-embedder": "^3.0.0",
"gh-pages": "^3.1.0", "gh-pages": "^3.1.0",
"identity-obj-proxy": "3.0.0",
"jest": "26.4.2",
"prettier": "2.0.5", "prettier": "2.0.5",
"react-test-renderer": "16.13.1",
"tailwindcss": "^1.7.6" "tailwindcss": "^1.7.6"
}, },
"keywords": [ "keywords": [
@@ -44,7 +49,7 @@
"start": "npm run develop", "start": "npm run develop",
"serve": "gatsby serve", "serve": "gatsby serve",
"clean": "gatsby clean", "clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1", "test": "jest",
"deploy": "gatsby build --prefix-paths && gh-pages -d public -b master" "deploy": "gatsby build --prefix-paths && gh-pages -d public -b master"
}, },
"repository": { "repository": {
@@ -0,0 +1,30 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Title renders correctly 1`] = `
<div
className="flex justify-center items-start flex-col w-full px-2 sm:px-6 mb-10"
>
<div
className="text-xl sm:text-2xl font-bold font-title mt-2 mb-2"
>
Title
</div>
<div
className="flex justify-start items-center w-full text-regular text-xs sm:text-lg"
>
<input
className="outline-none w-24 sm:w-40 mr-10 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700 prefix"
id="title-prefix"
onChange={[Function]}
value="Hi 👋, I'm"
/>
<input
className="outline-none placeholder-gray-700 w-1/2 sm:w-1/3 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700"
id="title-name"
onChange={[Function]}
placeholder="name"
value=""
/>
</div>
</div>
`;
+13
View File
@@ -0,0 +1,13 @@
import React from "react"
import renderer from "react-test-renderer"
import Title from "../title"
describe("Title", () => {
it("renders correctly", () => {
const tree = renderer
.create(<Title prefix={{ title: "Hi 👋, I'm" }} data={{ title: "" }} />)
.toJSON()
expect(tree).toMatchSnapshot()
})
})
+120 -3
View File
@@ -1,10 +1,11 @@
import React from "react" import React, { useState, useEffect } from "react"
import { withPrefix } from "gatsby" import { withPrefix } from "gatsby"
import { latestBlogs } from "../utils/workflows" import { latestBlogs } from "../utils/workflows"
import links from "../constants/page-links" import links from "../constants/page-links"
import { isMediumUsernameValid } from "../utils/validation" import { isMediumUsernameValid, isGitHubUsernameValid } from "../utils/validation"
import { ToolsIcon, XCircleIcon } from "@primer/octicons-react";
const AddonsItem = ({ inputId, inputChecked, onInputChange, ...props }) => { const AddonsItem = ({inputId, inputChecked, onInputChange, Icon, onIconClick, ...props}) => {
return ( return (
<div className="py-2 flex justify-start items-center text-sm sm:text-lg"> <div className="py-2 flex justify-start items-center text-sm sm:text-lg">
<label htmlFor={inputId} className="cursor-pointer flex items-center"> <label htmlFor={inputId} className="cursor-pointer flex items-center">
@@ -16,11 +17,94 @@ const AddonsItem = ({ inputId, inputChecked, onInputChange, ...props }) => {
/> />
<span className="pl-4">{props.children}</span> <span className="pl-4">{props.children}</span>
</label> </label>
{
Icon?
<button onClick={onIconClick} className="flex ml-3 focus:bg-gray-400" style={{outline: "none"}}>
<Icon className="transform scale-100 md:scale-125" />
</button>
:''
}
</div>
)
}
const CustomizeBadge = ({githubName, badgeOptions, onBadgeUpdate}) => {
return (
<div className={`border-2 border-solid border-gray-900 bg-gray-100 p-2 ml-8`} style={{maxWidth: '21rem'}}>
<header className="text-base sm:text-lg">Customize Badge</header>
<hr className="border-gray-500"/>
<div className="text-sm sm:text-lg flex flex-col mt-2 ml-0 md:ml-4">
<label htmlFor="badge-style">Style:&nbsp;
<select
id="badge-style"
onChange={(e) => onBadgeUpdate('badgeStyle', e.target.value)}
value = {badgeOptions.badgeStyle}
>
<option value="flat">Flat</option>
<option value="flat-square">Flat Square</option>
<option value="plastic">Plastic</option>
</select>
</label>
<label htmlFor="badge-color">Color:&nbsp;
<input
type="color"
id="badge-color"
defaultValue={`#${badgeOptions.badgeColor}`}
className="w-6"
onChange={(e) => onBadgeUpdate('badgeColor', e.target.value.replace('#', ''))}
/>
</label>
<label htmlFor="badge-label-text">Label Text:&nbsp;
<input
type="text"
id="badge-label-text"
placeholder="Profile views"
className="w-2/4 bg-gray-300 pl-2"
onChange={(e) => onBadgeUpdate('badgeLabel', e.target.value.trim())}
defaultValue={badgeOptions.badgeLabel}
/>
</label>
<span className="mt-2 flex items-center">
Preview:&nbsp;
{
isGitHubUsernameValid(githubName)?
<img
src={`https://komarev.com/ghpvc/`
+ `?username=${githubName}`
+ `&label=${encodeURI(badgeOptions.badgeLabel)}`
+ `&color=${badgeOptions.badgeColor}`
+ `&style=${badgeOptions.badgeStyle}`
}
/>
: <span className="text-xxs md:text-sm text-red-600">Invalid GitHub username</span>
}
</span>
</div>
</div> </div>
) )
} }
const Addons = props => { const Addons = props => {
const [customizeBadgeOpen, setCustomizeOpen] = useState(false);
const [debounce, setDebounce] = useState(undefined);
const [badgeOptions, setBadgeOptions] = useState({
badgeStyle: props.data.badgeStyle,
badgeColor: props.data.badgeColor,
badgeLabel: props.data.badgeLabel
});
useEffect(() => {
setBadgeOptions({
badgeStyle: props.data.badgeStyle,
badgeColor: props.data.badgeColor,
badgeLabel: props.data.badgeLabel
})
}, [props.data.badgeStyle, props.data.badgeColor, props.data.badgeLabel])
const blogPostPorkflow = () => { const blogPostPorkflow = () => {
let payload = { let payload = {
dev: { dev: {
@@ -48,6 +132,20 @@ const Addons = props => {
tempElement.click() tempElement.click()
document.body.removeChild(tempElement) document.body.removeChild(tempElement)
} }
const onCustomizeClick = () => {
setCustomizeOpen(!customizeBadgeOpen);
}
const onBadgeUpdate = (option, value) => {
const callback = () => {
let newVal = (option==='badgeLabel' && value==='')?'Profile views':value;
setBadgeOptions({...badgeOptions, [option]: newVal});
props.handleDataChange(option, {target: {value: newVal}})
}
clearTimeout(debounce);
setDebounce(setTimeout(callback, 300));
}
return ( return (
<div className="flex justify-center items-start flex-col w-full px-2 sm:px-6 mb-10"> <div className="flex justify-center items-start flex-col w-full px-2 sm:px-6 mb-10">
<div className="text-xl sm:text-2xl font-bold font-title mt-2 mb-2"> <div className="text-xl sm:text-2xl font-bold font-title mt-2 mb-2">
@@ -57,9 +155,20 @@ const Addons = props => {
inputId="visitors-count" inputId="visitors-count"
inputChecked={props.data.visitorsBadge} inputChecked={props.data.visitorsBadge}
onInputChange={() => props.handleCheckChange("visitorsBadge")} onInputChange={() => props.handleCheckChange("visitorsBadge")}
Icon={ customizeBadgeOpen ? XCircleIcon : ToolsIcon }
onIconClick={onCustomizeClick}
> >
display visitors count badge display visitors count badge
</AddonsItem> </AddonsItem>
{
customizeBadgeOpen?
<CustomizeBadge
githubName={props.social.github}
badgeOptions={badgeOptions}
onBadgeUpdate={onBadgeUpdate}
/>
: ''
}
<AddonsItem <AddonsItem
inputId="github-profile-trophy" inputId="github-profile-trophy"
inputChecked={props.data.githubProfileTrophy} inputChecked={props.data.githubProfileTrophy}
@@ -81,6 +190,13 @@ const Addons = props => {
> >
display top skills display top skills
</AddonsItem> </AddonsItem>
<AddonsItem
inputId="twitter-badge"
inputChecked={props.data.twitterBadge}
onInputChange={() => props.handleCheckChange("twitterBadge")}
>
display twitter badge
</AddonsItem>
<AddonsItem <AddonsItem
inputId="dev-dynamic-blogs" inputId="dev-dynamic-blogs"
inputChecked={props.data.devDynamicBlogs} inputChecked={props.data.devDynamicBlogs}
@@ -113,6 +229,7 @@ const Addons = props => {
download download
<span <span
onClick={blogPostPorkflow} onClick={blogPostPorkflow}
onKeyDown={(e) => e.keyCode === 13 && blogPostPorkflow()}
role="button" role="button"
tabIndex="0" tabIndex="0"
style={{ cursor: "pointer", color: "#002ead" }} style={{ cursor: "pointer", color: "#002ead" }}
+7 -2
View File
@@ -2,7 +2,9 @@ import React from "react"
const Donate = () => { const Donate = () => {
return ( return (
<> <>
<div className="text-center text-4xl my-2">Support 🙏</div> <div className="text-center text-4xl my-2">Support&nbsp;
<span role="img" aria-label="praying hand emoji">🙏</span>
</div>
<div className="flex flex-col sm:flex-row items-start justify-between"> <div className="flex flex-col sm:flex-row items-start justify-between">
<div className="w-full sm:w-2/3"> <div className="w-full sm:w-2/3">
<div className="text-2xl mb-2"> <div className="text-2xl mb-2">
@@ -28,12 +30,13 @@ const Donate = () => {
</div> </div>
</div> </div>
<div className="w-full sm:w-1/3 flex flex-col justify-center items-center"> <div className="w-full sm:w-1/3 flex flex-col justify-center items-center">
Tip💰 <span>Tip<span role="img" aria-label="Dollar medal">💰</span></span>
{/* Ko-Fi */} {/* Ko-Fi */}
<a <a
href="https://ko-fi.com/A0A81XXSX" href="https://ko-fi.com/A0A81XXSX"
className="flex items-center justify-evenly bg-red-500 text-white py-2 px-4 my-2" className="flex items-center justify-evenly bg-red-500 text-white py-2 px-4 my-2"
target="_blank" target="_blank"
rel="noreferrer"
> >
<img <img
className="w-6 h-6 mr-2" className="w-6 h-6 mr-2"
@@ -47,6 +50,7 @@ const Donate = () => {
href="https://www.paypal.me/rahuldkjain/10" href="https://www.paypal.me/rahuldkjain/10"
className="flex items-center justify-evenly bg-blue-500 text-white py-2 px-4 my-2" className="flex items-center justify-evenly bg-blue-500 text-white py-2 px-4 my-2"
target="_blank" target="_blank"
rel="noreferrer"
> >
<img <img
className="w-6 h-6 mr-2" className="w-6 h-6 mr-2"
@@ -60,6 +64,7 @@ const Donate = () => {
href="https://www.buymeacoffee.com/rahuldkjain" href="https://www.buymeacoffee.com/rahuldkjain"
className="flex items-center justify-evenly bg-orange-500 text-white py-2 px-4 my-2" className="flex items-center justify-evenly bg-orange-500 text-white py-2 px-4 my-2"
target="_blank" target="_blank"
rel="noreferrer"
> >
<img <img
className="w-6 h-6 mr-2" className="w-6 h-6 mr-2"
+31 -1
View File
@@ -80,7 +80,11 @@ const Markdown = props => {
return "" return ""
} }
const VisitorsBadge = props => { const VisitorsBadge = props => {
let link = "https://komarev.com/ghpvc/?username=" + props.github let link = "https://komarev.com/ghpvc/?username="
+ props.github
+ `&label=${props.badgeOptions.badgeLabel}`
+ `&color=${props.badgeOptions.badgeColor}`
+ `&style=${props.badgeOptions.badgeStyle}`
if (props.show) { if (props.show) {
return ( return (
<> <>
@@ -92,6 +96,19 @@ const Markdown = props => {
} }
return "" return ""
} }
const TwitterBadge = props => {
let link = "https://img.shields.io/twitter/follow/" + props.twitter + "?logo=twitter&style=for-the-badge"
if (props.show) {
return (
<>
{`<p align="left"> <a href="${props.base}/${props.twitter}" target="blank"><img src="${link}" alt="${props.twitter}" /></a> </p>`}
<br />
<br />
</>
)
}
return ""
}
const GithubProfileTrophy = props => { const GithubProfileTrophy = props => {
let link = let link =
"https://github-profile-trophy.vercel.app/?username=" + props.github "https://github-profile-trophy.vercel.app/?username=" + props.github
@@ -223,6 +240,11 @@ const Markdown = props => {
<VisitorsBadge <VisitorsBadge
show={props.data.visitorsBadge} show={props.data.visitorsBadge}
github={props.social.github} github={props.social.github}
badgeOptions={{
badgeLabel: encodeURI(props.data.badgeLabel),
badgeColor: props.data.badgeColor,
badgeStyle: props.data.badgeStyle
}}
/> />
</> </>
<> <>
@@ -230,6 +252,11 @@ const Markdown = props => {
show={props.data.githubProfileTrophy} show={props.data.githubProfileTrophy}
github={props.social.github} github={props.social.github}
/> />
<TwitterBadge
base="https://twitter.com"
show={props.data.twitterBadge}
twitter={props.social.twitter}
/>
</> </>
<> <>
<DisplayWork <DisplayWork
@@ -276,6 +303,9 @@ const Markdown = props => {
project={props.data.contact} project={props.data.contact}
/> />
</> </>
<>
<DisplayWork prefix={props.prefix.resume} link={props.link.resume} />
</>
<> <>
<DisplayWork <DisplayWork
prefix={props.prefix.funFact} prefix={props.prefix.funFact}
+30 -2
View File
@@ -89,6 +89,7 @@ const MarkdownPreview = props => {
<DisplayWork prefix={prefix.ama} project={data.ama} /> <DisplayWork prefix={prefix.ama} project={data.ama} />
<DisplayWork prefix={prefix.portfolio} link={link.portfolio} /> <DisplayWork prefix={prefix.portfolio} link={link.portfolio} />
<DisplayWork prefix={prefix.blog} link={link.blog} /> <DisplayWork prefix={prefix.blog} link={link.blog} />
<DisplayWork prefix={prefix.resume} link={link.resume} />
<DisplayWork prefix={prefix.contact} project={data.contact} /> <DisplayWork prefix={prefix.contact} project={data.contact} />
<DisplayWork prefix={prefix.funFact} project={data.funFact} /> <DisplayWork prefix={prefix.funFact} project={data.funFact} />
</> </>
@@ -222,7 +223,11 @@ const MarkdownPreview = props => {
) )
} }
const VisitorsBadgePreview = props => { const VisitorsBadgePreview = props => {
let link = "https://komarev.com/ghpvc/?username=" + props.github let link = "https://komarev.com/ghpvc/?username="
+ props.github
+ `&label=${props.badgeOptions.badgeLabel}`
+ `&color=${props.badgeOptions.badgeColor}`
+ `&style=${props.badgeOptions.badgeStyle}`
if (props.show) { if (props.show) {
return ( return (
<div className="text-left my-2"> <div className="text-left my-2">
@@ -233,6 +238,20 @@ const MarkdownPreview = props => {
} }
return null return null
} }
const TwitterBadgePreview = props => {
let link = "https://img.shields.io/twitter/follow/" + props.twitter + "?logo=twitter&style=for-the-badge"
if (props.show) {
return (
<div className="text-left my-2">
{" "}
<a href="https://twitter.com/${props.twitter}" target="blank">
<img className="h-4 sm:h-6" src={link} alt={props.twitter} />
</a>{" "}
</div>
)
}
return null
}
const GithubProfileTrophyPreview = props => { const GithubProfileTrophyPreview = props => {
let link = let link =
"https://github-profile-trophy.vercel.app/?username=" + props.github "https://github-profile-trophy.vercel.app/?username=" + props.github
@@ -281,7 +300,7 @@ const MarkdownPreview = props => {
skills.forEach(skill => { skills.forEach(skill => {
if (props.skills[skill]) { if (props.skills[skill]) {
listSkills.push( listSkills.push(
<a href={skillWebsites[skill]} target="_blank"> <a href={skillWebsites[skill]} target="_blank" rel="noreferrer">
<img <img
className="mb-4 mr-4 h-6 w-6 sm:h-10 sm:w-10" className="mb-4 mr-4 h-6 w-6 sm:h-10 sm:w-10"
key={skill} key={skill}
@@ -308,11 +327,20 @@ const MarkdownPreview = props => {
<VisitorsBadgePreview <VisitorsBadgePreview
show={props.data.visitorsBadge} show={props.data.visitorsBadge}
github={props.social.github} github={props.social.github}
badgeOptions={{
badgeLabel: encodeURI(props.data.badgeLabel),
badgeColor: props.data.badgeColor,
badgeStyle: props.data.badgeStyle
}}
/> />
<GithubProfileTrophyPreview <GithubProfileTrophyPreview
show={props.data.githubProfileTrophy} show={props.data.githubProfileTrophy}
github={props.social.github} github={props.social.github}
/> />
<TwitterBadgePreview
show={props.data.twitterBadge}
twitter={props.social.twitter}
/>
<WorkPreview work={props} /> <WorkPreview work={props} />
<SocialPreview social={props.social} /> <SocialPreview social={props.social} />
<SkillsPreview skills={props.skills} /> <SkillsPreview skills={props.skills} />
+5 -5
View File
@@ -34,7 +34,7 @@ const Skills = props => {
<input <input
type="search" type="search"
onChange={(e) => update(e.target.value)} onChange={(e) => update(e.target.value)}
className="leading:none text-xs my-0 py-0 sm:text-xl rounded-sm border border-gray-600 hover:border-gray-900 focus:outline-none focus:shadow-outline p-2 m-2" className="leading:none text-xs my-0 py-1 px-2 sm:text-xl border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700 placeholder-gray-700"
placeholder="Search Skills" placeholder="Search Skills"
/> />
</div> </div>
@@ -47,12 +47,12 @@ const Skills = props => {
return filtered.length !== 0 return filtered.length !== 0
}) })
.map(key => ( .map(key => (
<div key={key}> <div key={key} className="divide-y divide-gray-500">
<div className="text-sm sm:text-xl text-gray-900 text-left border-b border-r p-2 border-gray-400 m-2 rounded-sm"> <div className="text-sm sm:text-xl text-gray-900 text-left py-1">
{categorizedSkills[key].title} {categorizedSkills[key].title}
</div> </div>
<div className="flex justify-start items-center flex-wrap w-full mb-6 pl-4 sm:pl-10"> <div className="flex justify-start items-center flex-wrap w-full mb-6 pl-4 sm:pl-10">
{categorizedSkills[key].skills {categorizedSkills[key].skills
.filter(skill => { .filter(skill => {
return skill.includes(search.toLowerCase()) return skill.includes(search.toLowerCase())
}) })
@@ -61,7 +61,7 @@ const Skills = props => {
</div> </div>
))} ))}
</div> </div>
) )
} }
export default Skills export default Skills
+16
View File
@@ -151,6 +151,22 @@ const Work = props => {
onChange={event => props.handleLinkChange("blog", event)} onChange={event => props.handleLinkChange("blog", event)}
/> />
</div> </div>
<div className="text-xs sm:text-lg flex flex-col sm:flex-row mb-10 justify-center sm:justify-start items-center sm:items-start w-full px-4 sm:px-0">
<input
id="resume-prefix"
className="outline-none mr-8 w-full sm:w-1/3 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700"
value={props.prefix.resume}
onChange={event => props.handlePrefixChange("resume", event)}
/>
<input
id="resume"
placeholder="resume link"
className="outline-none placeholder-gray-700 mr-8 sm:mr-0 text-blue-700 w-full sm:w-1/3 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700"
value={props.link.resume}
onChange={event => props.handleLinkChange("resume", event)}
/>
</div>
<div className="text-xs sm:text-lg flex flex-col sm:flex-row mb-10 justify-center sm:justify-start items-center sm:items-start w-full px-4 sm:px-0"> <div className="text-xs sm:text-lg flex flex-col sm:flex-row mb-10 justify-center sm:justify-start items-center sm:items-start w-full px-4 sm:px-0">
<input <input
id="funFact-prefix" id="funFact-prefix"
+44 -2
View File
@@ -11,6 +11,7 @@ const categorizedSkills = {
"javascript", "javascript",
"typescript", "typescript",
"php", "php",
"perl",
"ruby", "ruby",
"scala", "scala",
"python", "python",
@@ -62,6 +63,7 @@ const categorizedSkills = {
"rabbitMQ", "rabbitMQ",
"hadoop", "hadoop",
"nginx", "nginx",
"openresty",
], ],
}, },
@@ -97,7 +99,8 @@ const categorizedSkills = {
"hive", "hive",
"realm", "realm",
"mariadb", "mariadb",
"elasticsearch" "cockroachdb",
"elasticsearch",
], ],
}, },
@@ -159,6 +162,7 @@ const categorizedSkills = {
skills: [ skills: [
"illustrator", "illustrator",
"photoshop", "photoshop",
"xd",
"figma", "figma",
"blender", "blender",
"sketch", "sketch",
@@ -169,7 +173,19 @@ const categorizedSkills = {
static_site_generator: { static_site_generator: {
title: "Static Site Generators", title: "Static Site Generators",
skills: ["gatsby", "gridsome", "hugo", "jekyll", "nextjs", "nuxtjs"], skills: [
"gatsby",
"gridsome",
"hugo",
"jekyll",
"nextjs",
"nuxtjs",
"11ty",
"scully",
"sculpin",
"sapper",
"vuepress"
],
}, },
game_engines:{ game_engines:{
@@ -246,12 +262,18 @@ const icons = {
"https://devicons.github.io/devicon/devicon.git/icons/nginx/nginx-original.svg", "https://devicons.github.io/devicon/devicon.git/icons/nginx/nginx-original.svg",
nodejs: nodejs:
"https://devicons.github.io/devicon/devicon.git/icons/nodejs/nodejs-original-wordmark.svg", "https://devicons.github.io/devicon/devicon.git/icons/nodejs/nodejs-original-wordmark.svg",
openresty:
"https://symbols-electrical.getvecta.com/stencil_25/66_openresty.403a21ca72.svg",
oracle: oracle:
"https://devicons.github.io/devicon/devicon.git/icons/oracle/oracle-original.svg", "https://devicons.github.io/devicon/devicon.git/icons/oracle/oracle-original.svg",
photoshop: photoshop:
"https://devicons.github.io/devicon/devicon.git/icons/photoshop/photoshop-plain.svg", "https://devicons.github.io/devicon/devicon.git/icons/photoshop/photoshop-plain.svg",
xd:
"https://cdn.worldvectorlogo.com/logos/adobe-xd.svg",
php: php:
"https://devicons.github.io/devicon/devicon.git/icons/php/php-original.svg", "https://devicons.github.io/devicon/devicon.git/icons/php/php-original.svg",
perl:
"https://api.iconify.design/logos-perl.svg",
postgresql: postgresql:
"https://devicons.github.io/devicon/devicon.git/icons/postgresql/postgresql-original-wordmark.svg", "https://devicons.github.io/devicon/devicon.git/icons/postgresql/postgresql-original-wordmark.svg",
python: python:
@@ -339,6 +361,7 @@ const icons = {
nextjs: "https://cdn.worldvectorlogo.com/logos/nextjs-3.svg", nextjs: "https://cdn.worldvectorlogo.com/logos/nextjs-3.svg",
reactnative: "https://reactnative.dev/img/header_logo.svg", reactnative: "https://reactnative.dev/img/header_logo.svg",
mariadb: "https://www.vectorlogo.zone/logos/mariadb/mariadb-icon.svg", mariadb: "https://www.vectorlogo.zone/logos/mariadb/mariadb-icon.svg",
cockroachdb: "https://worldvectorlogo.com/es/download/cockroachdb.svg",
objectivec: objectivec:
"https://www.vectorlogo.zone/logos/apple_objectivec/apple_objectivec-icon.svg", "https://www.vectorlogo.zone/logos/apple_objectivec/apple_objectivec-icon.svg",
clojure: clojure:
@@ -376,6 +399,16 @@ const icons = {
"https://www.vectorlogo.zone/logos/elastic/elastic-icon.svg", "https://www.vectorlogo.zone/logos/elastic/elastic-icon.svg",
circleci: circleci:
"https://www.vectorlogo.zone/logos/circleci/circleci-icon.svg", "https://www.vectorlogo.zone/logos/circleci/circleci-icon.svg",
scully:
"https://raw.githubusercontent.com/scullyio/scully/main/assets/logos/SVG/scullyio-icon.svg",
"11ty":
"https://gist.githubusercontent.com/vivek32ta/c7f7bf583c1fb1c58d89301ea40f37fd/raw/f4c85cce5790758286b8f155ef9a177710b995df/11ty.svg",
sculpin:
"https://gist.githubusercontent.com/vivek32ta/c7f7bf583c1fb1c58d89301ea40f37fd/raw/1782aef8672484698c0dd407f900c4a329ed5bc4/sculpin.svg",
sapper:
"https://raw.githubusercontent.com/bestofjs/bestofjs-webui/master/public/logos/sapper.svg",
vuepress:
"https://raw.githubusercontent.com/AliasIO/wappalyzer/master/src/drivers/webextension/images/icons/VuePress.svg",
unity: unity:
"https://www.vectorlogo.zone/logos/unity3d/unity3d-icon.svg" "https://www.vectorlogo.zone/logos/unity3d/unity3d-icon.svg"
} }
@@ -415,9 +448,12 @@ const skillWebsites = {
mysql: "https://www.mysql.com/", mysql: "https://www.mysql.com/",
nginx: "https://www.nginx.com", nginx: "https://www.nginx.com",
nodejs: "https://nodejs.org", nodejs: "https://nodejs.org",
openresty: "https://openresty.org/",
oracle: "https://www.oracle.com/", oracle: "https://www.oracle.com/",
photoshop: "https://www.photoshop.com/en", photoshop: "https://www.photoshop.com/en",
xd: "https://www.adobe.com/products/xd.html",
php: "https://www.php.net", php: "https://www.php.net",
perl: "https://www.perl.org/",
postgresql: "https://www.postgresql.org", postgresql: "https://www.postgresql.org",
python: "https://www.python.org", python: "https://www.python.org",
rails: "https://rubyonrails.org", rails: "https://rubyonrails.org",
@@ -477,6 +513,7 @@ const skillWebsites = {
nextjs: "https://nextjs.org/", nextjs: "https://nextjs.org/",
reactnative: "https://reactnative.dev/", reactnative: "https://reactnative.dev/",
mariadb: "https://mariadb.org/", mariadb: "https://mariadb.org/",
cockroachdb: "https://www.cockroachlabs.com/product/cockroachdb/",
objectivec: "", objectivec: "",
clojure: "", clojure: "",
haskell: "", haskell: "",
@@ -500,6 +537,11 @@ const skillWebsites = {
grafana: "https://grafana.com", grafana: "https://grafana.com",
elasticsearch: "https://www.elastic.co", elasticsearch: "https://www.elastic.co",
circleci: "https://circleci.com", circleci: "https://circleci.com",
scully: "https://scully.io/",
sculpin: "https://sculpin.io/",
"11ty": "https://www.11ty.dev/",
sapper: "https://sapper.svelte.dev/",
vuepress: "https://vuepress.vuejs.org/",
unity: "https://unity.com/" unity: "https://unity.com/"
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

+52 -38
View File
@@ -27,6 +27,7 @@ import SEO from "../components/seo"
import { import {
isGitHubUsernameValid, isGitHubUsernameValid,
isMediumUsernameValid, isMediumUsernameValid,
isTwitterUsernameValid
} from "../utils/validation" } from "../utils/validation"
import Layout from "../components/layout" import Layout from "../components/layout"
@@ -38,9 +39,11 @@ const DEFAULT_PREFIX = {
helpWith: "🤝 Im looking for help with", helpWith: "🤝 Im looking for help with",
ama: "💬 Ask me about", ama: "💬 Ask me about",
contact: "📫 How to reach me", contact: "📫 How to reach me",
resume: "📄 Know about my experiences",
funFact: "⚡ Fun fact", funFact: "⚡ Fun fact",
portfolio: "👨‍💻 All of my projects are available at", portfolio: "👨‍💻 All of my projects are available at",
blog: "📝 I regulary write articles on", blog: "📝 I regulary write articles on",
} }
const DEFAULT_DATA = { const DEFAULT_DATA = {
@@ -53,7 +56,11 @@ const DEFAULT_DATA = {
ama: "", ama: "",
contact: "", contact: "",
funFact: "", funFact: "",
twitterBadge: false,
visitorsBadge: false, visitorsBadge: false,
badgeStyle: "flat",
badgeColor: "0e75b6",
badgeLabel: "Profile views",
githubProfileTrophy: false, githubProfileTrophy: false,
githubStats: false, githubStats: false,
topLanguages: false, topLanguages: false,
@@ -68,6 +75,7 @@ const DEFAULT_LINK = {
helpWith: "", helpWith: "",
portfolio: "", portfolio: "",
blog: "", blog: "",
resume: "",
} }
const DEFAULT_SOCIAL = { const DEFAULT_SOCIAL = {
@@ -231,6 +239,10 @@ const IndexPage = () => {
if (social.github && isGitHubUsernameValid(social.github)) { if (social.github && isGitHubUsernameValid(social.github)) {
generate() generate()
} }
} else if (data.twitterBadge) {
if (social.twitter && isTwitterUsernameValid(social.twitter)) {
generate()
}
} else if (social.github) { } else if (social.github) {
if (isGitHubUsernameValid(social.github)) { if (isGitHubUsernameValid(social.github)) {
generate() generate()
@@ -365,10 +377,10 @@ const IndexPage = () => {
return return
} }
setPrefix(cache.prefix || DEFAULT_PREFIX) setPrefix(cache.prefix ? {...DEFAULT_PREFIX, ...cache.prefix} : DEFAULT_PREFIX)
setData(cache.data || DEFAULT_DATA) setData(cache.data ? {...DEFAULT_DATA, ...cache.data} : DEFAULT_DATA)
setLink(cache.link || DEFAULT_LINK) setLink(cache.link ? {...DEFAULT_LINK, ...cache.link} : DEFAULT_LINK)
setSocial(cache.social || DEFAULT_SOCIAL) setSocial(cache.social ? {...DEFAULT_SOCIAL, ...cache.social} : DEFAULT_SOCIAL)
const cacheSkills = mergeDefaultWithNewDataSkills( const cacheSkills = mergeDefaultWithNewDataSkills(
DEFAULT_SKILLS, DEFAULT_SKILLS,
@@ -470,6 +482,7 @@ const IndexPage = () => {
data={data} data={data}
social={social} social={social}
handleCheckChange={handleCheckChange} handleCheckChange={handleCheckChange}
handleDataChange={handleDataChange}
/> />
<div className="section"> <div className="section">
{(data.visitorsBadge || {(data.visitorsBadge ||
@@ -520,6 +533,20 @@ const IndexPage = () => {
) : ( ) : (
"" ""
)} )}
{data.twitterBadge && !social.twitter ? (
<div className="warning">
* Please add twitter username to use these add-ons
</div>
) : (
""
)}
{social.twitter && !isTwitterUsernameValid(social.twitter) ? (
<div className="warning">
* Twitter username is invalid, please add a valid username
</div>
) : (
""
)}
</div> </div>
<div className="flex items-center justify-center w-full"> <div className="flex items-center justify-center w-full">
<div <div
@@ -527,6 +554,7 @@ const IndexPage = () => {
tabIndex="0" tabIndex="0"
role="button" role="button"
onClick={handleGenerate} onClick={handleGenerate}
onKeyDown={(e) => e.keyCode === 13 && handleGenerate()}
> >
Generate README Generate README
</div> </div>
@@ -538,21 +566,17 @@ const IndexPage = () => {
{generateMarkdown || generatePreview ? ( {generateMarkdown || generatePreview ? (
<div className="markdown-section p-4 sm:py-4 sm:px-10"> <div className="markdown-section p-4 sm:py-4 sm:px-10">
<div className="w-full flex justify-between items-center"> <div className="w-full flex justify-between items-center">
<div <button
className="cursor-pointer text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1"
tabIndex="0"
role="button"
onClick={handleBackToEdit} onClick={handleBackToEdit}
> >
<ArrowLeftIcon size={16} /> <ArrowLeftIcon size={24} />
<span className="hidden sm:block"> back to edit</span> <span className="hidden sm:block"> back to edit</span>
</div> </button>
<div <button
className="cursor-pointer text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1"
tabIndex="0"
id="copy-button" id="copy-button"
role="button"
onClick={handleCopyToClipboard} onClick={handleCopyToClipboard}
> >
{copyObj.isCopied === true ? ( {copyObj.isCopied === true ? (
@@ -563,38 +587,32 @@ const IndexPage = () => {
<span className="hidden sm:block" id="copy-markdown"> <span className="hidden sm:block" id="copy-markdown">
{copyObj.copiedText} {copyObj.copiedText}
</span> </span>
</div> </button>
<div <button
className="cursor-pointer text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1"
tabIndex="0"
id="download-md-button" id="download-md-button"
role="button"
onClick={handleDownloadMarkdown} onClick={handleDownloadMarkdown}
> >
<DownloadIcon size={24} /> <DownloadIcon size={24} />
<span className="hidden sm:block" id="download-markdown"> <span className="hidden sm:block" id="download-markdown">
download markdown download markdown
</span> </span>
</div> </button>
<div <button
className="cursor-pointer text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1"
tabIndex="0"
id="download-json-button" id="download-json-button"
role="button"
onClick={handleDownloadJson} onClick={handleDownloadJson}
> >
<FileCodeIcon size={24} /> <FileCodeIcon size={24} />
<span className="hidden sm:block" id="download-json"> <span className="hidden sm:block" id="download-json">
download backup download backup
</span> </span>
</div> </button>
<div <button
className="cursor-pointer text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1"
tabIndex="0"
role="button"
onClick={handleGeneratePreview} onClick={handleGeneratePreview}
> >
{previewMarkdown.isPreview ? ( {previewMarkdown.isPreview ? (
@@ -605,7 +623,7 @@ const IndexPage = () => {
<span className="hidden sm:block ml-1" id="preview-markdown"> <span className="hidden sm:block ml-1" id="preview-markdown">
{previewMarkdown.buttonText} {previewMarkdown.buttonText}
</span> </span>
</div> </button>
</div> </div>
<div className="w-full flex justify-center items-center"> <div className="w-full flex justify-center items-center">
@@ -657,14 +675,12 @@ const IndexPage = () => {
new feature new feature
</span> </span>
</div> </div>
<div <button
className="text-xxs sm:text-sm border-2 w-auto px-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center" className="text-xxs sm:text-sm border-2 w-auto px-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center"
role="button"
tabIndex="0"
onClick={handleResetForm} onClick={handleResetForm}
> >
Reset form Reset form
</div> </button>
</div> </div>
<div className="w-full flex justify-start items-center my-4"> <div className="w-full flex justify-start items-center my-4">
<input <input
@@ -674,14 +690,12 @@ const IndexPage = () => {
value={restore} value={restore}
onChange={e => setRestore(e.target.value)} onChange={e => setRestore(e.target.value)}
/> />
<div <button
className="text-xxs sm:text-sm border-2 w-32 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1" className="text-xxs sm:text-sm border-2 w-32 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1"
role="button"
tabIndex="0"
onClick={handleRestore} onClick={handleRestore}
> >
Restore Restore
</div> </button>
</div> </div>
<div className="flex flex-col items-start justify-center"> <div className="flex flex-col items-start justify-center">
<div className="text-green-700 font-medium">Tips</div> <div className="text-green-700 font-medium">Tips</div>
+6 -1
View File
@@ -9,4 +9,9 @@ const isMediumUsernameValid = username => {
return true return true
} }
export { isGitHubUsernameValid, isMediumUsernameValid } const isTwitterUsernameValid = username => {
var pattern = /^[a-zA-Z0-9_]{1,15}$/
return pattern.test(username)
}
export { isGitHubUsernameValid, isMediumUsernameValid, isTwitterUsernameValid }