diff --git a/.eslintrc.json b/.eslintrc.json index 8c4cc1b5..056f0bce 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,7 @@ "browser": true, "es2021": true }, - "extends": ["plugin:react/recommended", "airbnb"], + "extends": ["plugin:react/recommended", "airbnb", "prettier"], "parserOptions": { "ecmaFeatures": { "jsx": true @@ -12,5 +12,7 @@ "sourceType": "module" }, "plugins": ["react"], - "rules": {} + "rules": { + "react/forbid-prop-types": 0 + } } diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..d37daa07 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx --no-install lint-staged diff --git a/.prettierrc b/.prettierrc index bde4900e..1592ecf9 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,14 +1,9 @@ { - "printWidth": 80, - "tabWidth": 2, - "useTabs": false, - "semi": true, "singleQuote": true, - "quoteProps": "as-needed", "jsxSingleQuote": false, + "tabWidth": 2, + "printWidth": 480, "trailingComma": "all", - "bracketSpacing": true, - "jsxBracketSameLine": true, - "arrowParens": "avoid", - "endOfLine": "auto" + "semi": true, + "exclude": ["node_modules", "codepipeline"] } diff --git a/package-lock.json b/package-lock.json index 1eb2e73d..d83d21b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6999,11 +6999,18 @@ "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==" }, "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", "requires": { - "follow-redirects": "1.5.10" + "follow-redirects": "^1.14.4" + }, + "dependencies": { + "follow-redirects": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + } } }, "axobject-query": { @@ -9305,6 +9312,14 @@ "type-fest": "0.15.1" }, "dependencies": { + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, "type-fest": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.15.1.tgz", @@ -14027,6 +14042,14 @@ } } }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, "babel-plugin-apply-mdx-type-prop": { "version": "2.0.0-next.8", "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-2.0.0-next.8.tgz", diff --git a/package.json b/package.json index f0145be5..8e60965c 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@primer/octicons-react": "^10.0.0", + "axios": "^0.24.0", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", "enzyme-to-json": "^3.6.1", diff --git a/src/components/addons.js b/src/components/addons.js deleted file mode 100644 index 7346f025..00000000 --- a/src/components/addons.js +++ /dev/null @@ -1,456 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { withPrefix } from 'gatsby'; -import { latestBlogs } from '../utils/workflows'; -import links from '../constants/page-links'; -import { isMediumUsernameValid, isGitHubUsernameValid } from '../utils/validation'; -import { ToolsIcon, XCircleIcon } from '@primer/octicons-react'; - -const AddonsItem = ({ inputId, inputChecked, onInputChange, Options, onIconClick, ...props }) => { - const [open, setOpen] = useState(false); - const Icon = open ? XCircleIcon : ToolsIcon; - - return ( - <> -
- - {Options && ( - - )} -
- {Options && open && Options} - - ); -}; - -const CustomizeOptions = ({ title, CustomizationOptions }) => ( -
-
{title}
-
-
{CustomizationOptions}
-
-); - -const CustomizeBadge = ({ githubName, badgeOptions, onBadgeUpdate }) => { - return ( - <> - - - - - - - - Preview:  - {isGitHubUsernameValid(githubName) ? ( - profile-visitors-count - ) : ( - Invalid GitHub username - )} - - - ); -}; - -const CustomizeGithubStatsBase = ({ prefix, options, onUpdate }) => ( - <> - - - - - - - - -); - -const CustomizeStreakStats = ({ prefix, options, onUpdate }) => ( - <> - - -); - -const Addons = (props) => { - 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 [githubStatsOptions, setGithubStatsOptions] = useState({ - ...props.data.githubStatsOptions, - }); - - useEffect(() => { - setGithubStatsOptions({ - ...props.data.githubStatsOptions, - }); - }, [props.data.githubStatsOptions]); - - const [topLanguagesOptions, setTopLanguagesOptions] = useState({ - ...props.data.topLanguagesOptions, - }); - - useEffect(() => { - setTopLanguagesOptions({ - ...props.data.topLanguagesOptions, - }); - }, [props.data.topLanguagesOptions]); - - const [streakStatsOptions, setStreakStatsOptions] = useState({ - ...props.data.streakStatsOptions, - }); - - useEffect(() => { - setStreakStatsOptions({ - ...props.data.streakStatsOptions, - }); - }, [props.data.streakStatsOptions]); - - const blogPostPorkflow = () => { - let payload = { - dev: { - show: props.data.devDynamicBlogs, - username: props.social.dev, - }, - medium: { - show: props.data.mediumDynamicBlogs, - username: props.social.medium, - }, - rssurl: { - show: props.data.rssDynamicBlogs, - username: props.social.rssurl, - }, - }; - var actionContent = latestBlogs(payload); - var tempElement = document.createElement('a'); - tempElement.setAttribute('href', 'data:text/yaml;charset=utf-8,' + encodeURIComponent(actionContent)); - tempElement.setAttribute('download', 'blog-post-workflow.yml'); - tempElement.style.display = 'none'; - document.body.appendChild(tempElement); - tempElement.click(); - document.body.removeChild(tempElement); - }; - - 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)); - }; - - const onStatsUpdate = (option, value) => { - const newStatsOptions = { ...githubStatsOptions, [option]: value }; - setGithubStatsOptions(newStatsOptions); - props.handleDataChange('githubStatsOptions', { - target: { value: newStatsOptions }, - }); - }; - - const onTopLangUpdate = (option, value) => { - const newLangOptions = { ...topLanguagesOptions, [option]: value }; - setTopLanguagesOptions(newLangOptions); - props.handleDataChange('topLanguagesOptions', { - target: { value: newLangOptions }, - }); - }; - - const onStreakStatsUpdate = (option, value) => { - const newStreakStatsOptions = { ...streakStatsOptions, [option]: value }; - setStreakStatsOptions(newStreakStatsOptions); - props.handleDataChange('streakStatsOptions', { - target: { value: newStreakStatsOptions }, - }); - }; - - return ( -
-
Add-ons
- props.handleCheckChange('visitorsBadge')} - Options={ - - } - /> - } - > - display visitors count badge - - props.handleCheckChange('githubProfileTrophy')} - > - display github trophy - - props.handleCheckChange('githubStats')} - Options={ - - } - /> - } - > - display github profile stats card - - props.handleCheckChange('topLanguages')} - Options={ - - } - /> - } - > - display top skills - - props.handleCheckChange('streakStats')} - Options={ - - } - /> - } - > - display github streak stats - - props.handleCheckChange('twitterBadge')} - > - display twitter badge - - props.handleCheckChange('devDynamicBlogs')} - > - display latest dev.to blogs dynamically (GitHub Action) - - props.handleCheckChange('mediumDynamicBlogs')} - > - display latest medium blogs dynamically (GitHub Action) - - props.handleCheckChange('rssDynamicBlogs')} - > - display latest blogs from your personal blog dynamically (GitHub Action) - - - {(props.data.devDynamicBlogs && props.social.dev) || - (props.data.rssDynamicBlogs && props.social.rssurl) || - (props.data.mediumDynamicBlogs && props.social.medium && isMediumUsernameValid(props.social.medium)) ? ( -
-
- download - e.keyCode === 13 && blogPostPorkflow()} - role="button" - tabIndex="0" - style={{ cursor: 'pointer', color: '#002ead' }} - > - {' '} - blog-post-workflow.yml - {' '} - file(learn - - {' '} - how to setup - - ) -
-
- ) : ( - '' - )} -
- ); -}; - -export default Addons; diff --git a/src/components/addons.jsx b/src/components/addons.jsx new file mode 100644 index 00000000..15cb1e4e --- /dev/null +++ b/src/components/addons.jsx @@ -0,0 +1,320 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { withPrefix } from 'gatsby'; +import { ToolsIcon, XCircleIcon } from '@primer/octicons-react'; +import latestBlogs from '../utils/workflows'; +import links from '../constants/page-links'; +import { isMediumUsernameValid, isGitHubUsernameValid } from '../utils/validation'; + +const AddonsItem = (props) => { + const { inputId, inputChecked, onInputChange, Options, children } = props; + const [open, setOpen] = useState(false); + const Icon = open ? XCircleIcon : ToolsIcon; + + return ( + <> +
+ + {Options && ( + + )} +
+ {Options && open && Options} + + ); +}; +AddonsItem.propTypes = { + inputId: PropTypes.string.isRequired, + inputChecked: PropTypes.bool.isRequired, + onInputChange: PropTypes.func.isRequired, + Options: PropTypes.element.isRequired, + children: PropTypes.element.isRequired, +}; + +const CustomizeOptions = ({ title, CustomizationOptions }) => ( +
+
{title}
+
+
{CustomizationOptions}
+
+); +CustomizeOptions.propTypes = { + title: PropTypes.string.isRequired, + CustomizationOptions: PropTypes.element.isRequired, +}; + +const CustomizeBadge = ({ githubName, badgeOptions, onBadgeUpdate }) => ( + <> + + + + + + + + Preview:  + {isGitHubUsernameValid(githubName) ? profile-visitors-count : Invalid GitHub username} + + +); +CustomizeBadge.propTypes = { + githubName: PropTypes.string.isRequired, + badgeOptions: PropTypes.object.isRequired, + onBadgeUpdate: PropTypes.func.isRequired, +}; + +const CustomizeGithubStatsBase = ({ prefix, options, onUpdate }) => ( + <> + + + + + + + + +); +CustomizeGithubStatsBase.propTypes = { + prefix: PropTypes.string.isRequired, + options: PropTypes.object.isRequired, + onUpdate: PropTypes.func.isRequired, +}; + +const CustomizeStreakStats = ({ prefix, options, onUpdate }) => ( + <> + + +); +CustomizeStreakStats.propTypes = { + prefix: PropTypes.string.isRequired, + options: PropTypes.object.isRequired, + onUpdate: PropTypes.func.isRequired, +}; + +const Addons = (props) => { + const { data, social, handleDataChange, handleCheckChange } = props; + const [debounce, setDebounce] = useState(undefined); + const [badgeOptions, setBadgeOptions] = useState({ + badgeStyle: data.badgeStyle, + badgeColor: data.badgeColor, + badgeLabel: data.badgeLabel, + }); + + useEffect(() => { + setBadgeOptions({ + badgeStyle: data.badgeStyle, + badgeColor: data.badgeColor, + badgeLabel: data.badgeLabel, + }); + }, [data.badgeStyle, data.badgeColor, data.badgeLabel]); + + const [githubStatsOptions, setGithubStatsOptions] = useState({ + ...data.githubStatsOptions, + }); + + useEffect(() => { + setGithubStatsOptions({ + ...data.githubStatsOptions, + }); + }, [data.githubStatsOptions]); + + const [topLanguagesOptions, setTopLanguagesOptions] = useState({ + ...data.topLanguagesOptions, + }); + + useEffect(() => { + setTopLanguagesOptions({ + ...data.topLanguagesOptions, + }); + }, [data.topLanguagesOptions]); + + const [streakStatsOptions, setStreakStatsOptions] = useState({ + ...data.streakStatsOptions, + }); + + useEffect(() => { + setStreakStatsOptions({ + ...data.streakStatsOptions, + }); + }, [data.streakStatsOptions]); + + const blogPostPorkflow = () => { + const payload = { + dev: { + show: data.devDynamicBlogs, + username: social.dev, + }, + medium: { + show: data.mediumDynamicBlogs, + username: social.medium, + }, + rssurl: { + show: data.rssDynamicBlogs, + username: social.rssurl, + }, + }; + const actionContent = latestBlogs(payload); + const tempElement = document.createElement('a'); + tempElement.setAttribute('href', `data:text/yaml;charset=utf-8,${encodeURIComponent(actionContent)}`); + tempElement.setAttribute('download', 'blog-post-workflow.yml'); + tempElement.style.display = 'none'; + document.body.appendChild(tempElement); + tempElement.click(); + document.body.removeChild(tempElement); + }; + + const onBadgeUpdate = (option, value) => { + const callback = () => { + const newVal = option === 'badgeLabel' && value === '' ? 'Profile views' : value; + setBadgeOptions({ ...badgeOptions, [option]: newVal }); + handleDataChange(option, { target: { value: newVal } }); + }; + clearTimeout(debounce); + setDebounce(setTimeout(callback, 300)); + }; + + const onStatsUpdate = (option, value) => { + const newStatsOptions = { ...githubStatsOptions, [option]: value }; + setGithubStatsOptions(newStatsOptions); + handleDataChange('githubStatsOptions', { + target: { value: newStatsOptions }, + }); + }; + + const onTopLangUpdate = (option, value) => { + const newLangOptions = { ...topLanguagesOptions, [option]: value }; + setTopLanguagesOptions(newLangOptions); + handleDataChange('topLanguagesOptions', { + target: { value: newLangOptions }, + }); + }; + + const onStreakStatsUpdate = (option, value) => { + const newStreakStatsOptions = { ...streakStatsOptions, [option]: value }; + setStreakStatsOptions(newStreakStatsOptions); + handleDataChange('streakStatsOptions', { + target: { value: newStreakStatsOptions }, + }); + }; + + return ( +
+
Add-ons
+ handleCheckChange('visitorsBadge')} Options={} />}> + display visitors count badge + + handleCheckChange('githubProfileTrophy')}> + display github trophy + + handleCheckChange('githubStats')} Options={} />}> + display github profile stats card + + handleCheckChange('topLanguages')} Options={} />}> + display top skills + + handleCheckChange('streakStats')} Options={} />}> + display github streak stats + + handleCheckChange('twitterBadge')}> + display twitter badge + + handleCheckChange('devDynamicBlogs')}> + display latest dev.to blogs dynamically (GitHub Action) + + handleCheckChange('mediumDynamicBlogs')}> + display latest medium blogs dynamically (GitHub Action) + + handleCheckChange('rssDynamicBlogs')}> + display latest blogs from your personal blog dynamically (GitHub Action) + + + {(data.devDynamicBlogs && social.dev) || (data.rssDynamicBlogs && social.rssurl) || (data.mediumDynamicBlogs && social.medium && isMediumUsernameValid(social.medium)) ? ( +
+
+ download + e.keyCode === 13 && blogPostPorkflow()} role="button" tabIndex="0" style={{ cursor: 'pointer', color: '#002ead' }}> + {' '} + blog-post-workflow.yml + {' '} + file(learn + + {' '} + how to setup + + ) +
+
+ ) : ( + '' + )} +
+ ); +}; + +export default Addons; +Addons.propTypes = { + data: PropTypes.object.isRequired, + social: PropTypes.object.isRequired, + handleDataChange: PropTypes.func.isRequired, + handleCheckChange: PropTypes.func.isRequired, +}; diff --git a/src/components/donate.js b/src/components/donate.js deleted file mode 100644 index a616232e..00000000 --- a/src/components/donate.js +++ /dev/null @@ -1,89 +0,0 @@ -import React from 'react'; -const Donate = () => { - return ( - <> -
- Support  - - 🙏 - -
-
-
-
Are you using the tool and happy with it to create your GitHub Profile?
-
Your kind support keeps open-source tools like this free for others.
-
- - tweet github profile readme generator - - Let the world know how you feel using this tool. Share with others on twitter. -
-
-
- - Tip - - 💰 - - - {/* Ko-Fi */} - - Buy ko-fi for rahuldkjain - Buy me a ko-fi - - {/* Paypal */} - - Donate rahuldkjain via paypal - {/* Donate rahuldkjain via paypal - Paypal */} - - {/* BuyMeACoffee */} - - Buy rahuldkjain A Coffee - Buy me a coffee - -
-
- - ); -}; - -export default Donate; diff --git a/src/components/donate.jsx b/src/components/donate.jsx new file mode 100644 index 00000000..945ac894 --- /dev/null +++ b/src/components/donate.jsx @@ -0,0 +1,54 @@ +import React from 'react'; + +const Donate = () => ( + <> +
+ Support  + + 🙏 + +
+
+
+
Are you using the tool and happy with it to create your GitHub Profile?
+
Your kind support keeps open-source tools like this free for others.
+
+ + tweet github profile readme generator + + Let the world know how you feel using this tool. Share with others on twitter. +
+
+
+ + Tip + + 💰 + + + {/* Ko-Fi */} + + Buy ko-fi for rahuldkjain + Buy me a ko-fi + + {/* Paypal */} + + Donate rahuldkjain via paypal + {/* Donate rahuldkjain via paypal + Paypal */} + + {/* BuyMeACoffee */} + + Buy rahuldkjain A Coffee + Buy me a coffee + +
+
+ +); + +export default Donate; diff --git a/src/components/footer.js b/src/components/footer.js deleted file mode 100644 index b7587bbc..00000000 --- a/src/components/footer.js +++ /dev/null @@ -1,104 +0,0 @@ -import React from 'react'; -import links from '../constants/page-links'; -import logo from '../images/mdg.png'; -import discord from '../images/Discord-Logo.png'; -import { Link } from 'gatsby'; -const Footer = () => { - return ( -
-
-
-

-
- github profile markdown generator logo -
- GitHub Profile{' '} - github profile markdown generator logo - README Generator -
-
-

-
-
-
- Pages -
-
- - Addons - -
-
- - Support - -
-
- - About - -
-
-
-
- More -
-
- - Github - -
-
- - Releases - -
-
- - Issues - -
-
- - Pull Requests - -
-
-
-
- Join Community -
-
- - Discord of the community - -
-
-
-
- Developed in India{' '} - - {' '} - 🇮🇳 - -
-
- ); -}; -export default Footer; diff --git a/src/components/footer.jsx b/src/components/footer.jsx new file mode 100644 index 00000000..58a4e1ea --- /dev/null +++ b/src/components/footer.jsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { Link } from 'gatsby'; +import links from '../constants/page-links'; +import logo from '../images/mdg.png'; +import discord from '../images/Discord-Logo.png'; + +const Footer = () => ( +
+
+
+

+
+ github profile markdown generator logo +
+ GitHub Profile github profile markdown generator logo + README Generator +
+
+

+
+
+
+ Pages +
+
+ + Addons + +
+
+ + Support + +
+
+ + About + +
+
+
+
+ More +
+
+ + Github + +
+
+ + Releases + +
+
+ + Issues + +
+
+ + Pull Requests + +
+
+
+
+ Join Community +
+
+ + Discord of the community + +
+
+
+
+ Developed in India{' '} + + {' '} + 🇮🇳 + +
+
+); +export default Footer; diff --git a/src/components/header.js b/src/components/header.jsx similarity index 74% rename from src/components/header.js rename to src/components/header.jsx index f913796d..82437ebb 100644 --- a/src/components/header.js +++ b/src/components/header.jsx @@ -1,13 +1,20 @@ import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; import { StarIcon, RepoForkedIcon } from '@primer/octicons-react'; -import logo from '../images/mdg.png'; -import links from '../constants/page-links'; import gsap from 'gsap'; import axios from 'axios'; import { Link } from 'gatsby'; import { act } from 'react-dom/test-utils'; +import links from '../constants/page-links'; +import logo from '../images/mdg.png'; const Header = (props) => { + const { heading } = props; + const [stats, setstats] = useState({ + starsCount: 0, + forksCount: 0, + }); + const shouldRequestStats = () => { const isFirstRequest = stats.starsCount === 0; const isVisible = window.document.visibilityState === 'visible'; @@ -17,24 +24,18 @@ const Header = (props) => { const fetchData = async () => { if (shouldRequestStats()) { - var response = await axios.get('https://api.github.com/repos/rahuldkjain/github-profile-readme-generator'); + const response = await axios.get('https://api.github.com/repos/rahuldkjain/github-profile-readme-generator'); - const { stargazers_count, forks_count } = response.data; + const { stargazers_count: stargazersCount, forks_count: forksCount } = response.data; act(() => setstats({ - starsCount: stargazers_count, - forksCount: forks_count, - }) + starsCount: stargazersCount, + forksCount, + }), ); } }; - - const [stats, setstats] = useState({ - starsCount: 0, - forksCount: 0, - }); - useEffect(() => { fetchData(); setInterval(fetchData, 60000); @@ -56,27 +57,18 @@ const Header = (props) => {

github profile markdown generator logo -
{props.heading}
+
{heading}

- +
Star this repo {stats.starsCount}
- +
Fork on GitHub @@ -89,3 +81,6 @@ const Header = (props) => { }; export default Header; +Header.propTypes = { + heading: PropTypes.string.isRequired, +}; diff --git a/src/components/layout.js b/src/components/layout.js deleted file mode 100644 index 53435748..00000000 --- a/src/components/layout.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import Header from './header'; -import Footer from './footer'; - -const Layout = ({ children }) => { - return ( -
-
-
-
-
{children}
-
-
-
-
- ); -}; -export default Layout; diff --git a/src/components/layout.jsx b/src/components/layout.jsx new file mode 100644 index 00000000..2e8a6ffa --- /dev/null +++ b/src/components/layout.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Header from './header'; +import Footer from './footer'; + +const Layout = ({ children }) => ( +
+
+
+
+
{children}
+
+
+
+
+); +export default Layout; + +Layout.defaultProps = { + children: '', +}; + +Layout.propTypes = { + children: PropTypes.element, +}; diff --git a/src/components/loader.js b/src/components/loader.jsx similarity index 50% rename from src/components/loader.js rename to src/components/loader.jsx index 73abc820..1fcb1609 100644 --- a/src/components/loader.js +++ b/src/components/loader.jsx @@ -1,9 +1,10 @@ import React, { useRef, useEffect } from 'react'; import gsap from 'gsap'; + const Loader = () => { - let arrow = useRef([]); + const arrow = useRef([]); useEffect(() => { - var tl = new gsap.timeline({ repeat: -1 }); + const tl = gsap.timeline({ repeat: -1 }); tl.fromTo( arrow.current, { @@ -16,7 +17,7 @@ const Loader = () => { stagger: 0.1, duration: 0.5, ease: 'Linear.easeNone', - } + }, ); tl.add('cp'); tl.fromTo( @@ -32,16 +33,46 @@ const Loader = () => { duration: 0.5, ease: 'Linear.easeNone', }, - 'cp-=0.3' + 'cp-=0.3', ); }); return (
- (arrow.current[0] = el)}>↓ - (arrow.current[1] = el)}>↓ - (arrow.current[2] = el)}>↓ - (arrow.current[3] = el)}>↓ - (arrow.current[4] = el)}>↓ + { + arrow.current[0] = el; + }} + > + ↓ + + { + arrow.current[1] = el; + }} + > + ↓ + + { + arrow.current[2] = el; + }} + > + ↓ + + { + arrow.current[3] = el; + }} + > + ↓ + + { + arrow.current[4] = el; + }} + > + ↓ +
); }; diff --git a/src/components/markdown.js b/src/components/markdown.js deleted file mode 100644 index 5e769e3a..00000000 --- a/src/components/markdown.js +++ /dev/null @@ -1,521 +0,0 @@ -import React from 'react'; -import { isMediumUsernameValid } from '../utils/validation'; -import { icons, skills, skillWebsites } from '../constants/skills'; -import { - githubStatsLinkGenerator, - topLanguagesLinkGenerator, - streakStatsLinkGenerator, -} from '../utils/link-generators'; -const Title = (props) => { - if (props.prefix && props.title) { - return ( - <> - {`

${props.prefix + ' ' + props.title}

`} -
- - ); - } - return ''; -}; -const SubTitle = (props) => { - if (props.subtitle) { - return ( - <> - {`

${props.subtitle}

`} -
-
- - ); - } - return ''; -}; -const SectionTitle = (props) => { - if (props.label) { - return ( - <> - {`

${props.label}

`} -
- - ); - } - return ''; -}; -const DisplayWork = (props) => { - if (props.prefix && props.project) { - if (props.link) { - return ( - <> - {`- ${props.prefix} [${props.project}](${props.link})`} -
-
- - ); - } else { - return ( - <> - {`- ${props.prefix} **${props.project}**`} -
-
- - ); - } - } - if (props.prefix && props.link) { - return ( - <> - {`- ${props.prefix} [${props.link}](${props.link})`} -
-
- - ); - } - return ''; -}; -const DisplaySocial = (props) => { - if (props.username) { - return ( - <> - {`
${props.username}`} -
- - ); - } - return ''; -}; -const VisitorsBadge = (props) => { - let link = - 'https://komarev.com/ghpvc/?username=' + - props.github + - `&label=${props.badgeOptions.badgeLabel}` + - `&color=${props.badgeOptions.badgeColor}` + - `&style=${props.badgeOptions.badgeStyle}`; - if (props.show) { - return ( - <> - {`

${props.github}

`} -
-
- - ); - } - return ''; -}; -const TwitterBadge = (props) => { - let link = 'https://img.shields.io/twitter/follow/' + props.twitter + '?logo=twitter&style=for-the-badge'; - if (props.show) { - return ( - <> - {`

${props.twitter}

`} -
-
- - ); - } - return ''; -}; -const GithubProfileTrophy = (props) => { - let link = 'https://github-profile-trophy.vercel.app/?username=' + props.github; - if (props.show) { - return ( - <> - {`

${props.github}

`} -
-
- - ); - } - return ''; -}; -const GitHubStats = ({ show, github, options }) => { - if (show) { - return ( - <> - {`

 ${github}

`} -
-
- - ); - } - return ''; -}; -const isSocial = (social) => { - return ( - social.dev || - social.twitter || - social.codepen || - social.codesandbox || - social.stackoverflow || - social.linkedin || - social.kaggle || - social.instagram || - social.fb || - social.dribbble || - social.behance || - social.medium || - social.youtube || - social.codechef || - social.hackerrank || - social.codeforces || - social.leetcode || - social.topcoder || - social.hackerearth || - social.geeks_for_geeks || - social.discord || - social.rssurl - ); -}; -const DisplaySkills = (props) => { - const listChosenSkills = []; - skills.forEach((skill) => { - if (props.skills[skill]) { - listChosenSkills.push( - ` - - ${skill} - - ` - ); - } - }); - return listChosenSkills.length > 0 ? ( - <> - - {`

${listChosenSkills.join(' ')}

`} -
-
- - ) : ( - '' - ); -}; -const DisplayDynamicBlogs = (props) => { - if (props.show) { - return ( - <> - {`### Blogs posts`} -
- {``} -
- {``} -

- - ); - } - return ''; -}; -const DisplayTopLanguages = (props) => { - if (props.show) { - if (!props.showStats) { - return ( - <> - {`

${props.github}

`} -
-
- - ); - } - return ( - <> - {`

${props.github}

`} -
-
- - ); - } - return ''; -}; -const DisplayStreakStats = (props) => { - if (props.show) { - return ( - <> - {`

${props.github}

`} -
-
- - ); - } - return ''; -}; -const DisplaySupport = (props) => { - let viewSupport = false; - Object.keys(props.support).forEach((key) => { - if (props.support[key]) { - viewSupport = true; - } - }); - return viewSupport ? ( -
- - {`

`} - {props.support.buyMeACoffee && - ` - ${props.support.buyMeACoffee}`} - {props.support.buyMeAKofi && - ` - ${props.support.buyMeAKofi}`} - {`



`} -
-
-
- ) : ( - '' - ); -}; -const Markdown = (props) => { - const icon_base_url = - 'https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/icons/Social/'; - - return ( -
- <> - - </> - <> - <SubTitle subtitle={props.data.subtitle} /> - </> - <> - <VisitorsBadge - show={props.data.visitorsBadge} - github={props.social.github} - badgeOptions={{ - badgeLabel: encodeURI(props.data.badgeLabel), - badgeColor: props.data.badgeColor, - badgeStyle: props.data.badgeStyle, - }} - /> - </> - <> - <GithubProfileTrophy show={props.data.githubProfileTrophy} github={props.social.github} /> - <TwitterBadge base="https://twitter.com" show={props.data.twitterBadge} twitter={props.social.twitter} /> - </> - <> - <DisplayWork prefix={props.prefix.currentWork} project={props.data.currentWork} link={props.link.currentWork} /> - </> - <> - <DisplayWork prefix={props.prefix.currentLearn} project={props.data.currentLearn} /> - </> - <> - <DisplayWork - prefix={props.prefix.collaborateOn} - project={props.data.collaborateOn} - link={props.link.collaborateOn} - /> - </> - <> - <DisplayWork prefix={props.prefix.helpWith} project={props.data.helpWith} link={props.link.helpWith} /> - </> - <> - <DisplayWork prefix={props.prefix.portfolio} link={props.link.portfolio} /> - </> - <> - <DisplayWork prefix={props.prefix.blog} link={props.link.blog} /> - </> - <> - <DisplayWork prefix={props.prefix.ama} project={props.data.ama} /> - </> - <> - <DisplayWork prefix={props.prefix.contact} project={props.data.contact} /> - </> - <> - <DisplayWork prefix={props.prefix.resume} link={props.link.resume} /> - </> - <> - <DisplayWork prefix={props.prefix.funFact} project={props.data.funFact} /> - </> - <> - <DisplayDynamicBlogs - show={ - (props.data.devDynamicBlogs && props.social.dev) || - (props.data.rssDynamicBlogs && props.social.rssurl) || - (props.data.mediumDynamicBlogs && props.social.medium && isMediumUsernameValid(props.social.medium)) - } - /> - </> - {isSocial(props.social) ? ( - <> - <SectionTitle label="Connect with me:" /> - {`<p align="left">`} - </> - ) : ( - '' - )} - <br /> - <> - <DisplaySocial base="https://codepen.io" icon={icon_base_url + 'codepen.svg'} username={props.social.codepen} /> - </> - <> - <DisplaySocial base="https://dev.to" icon={icon_base_url + 'devto.svg'} username={props.social.dev} /> - </> - <> - <DisplaySocial - base="https://twitter.com" - icon={icon_base_url + 'twitter.svg'} - username={props.social.twitter} - /> - </> - <> - <DisplaySocial - base="https://linkedin.com/in" - icon={icon_base_url + 'linked-in-alt.svg'} - username={props.social.linkedin} - /> - </> - <> - <DisplaySocial - base="https://stackoverflow.com/users" - icon={icon_base_url + 'stack-overflow.svg'} - username={props.social.stackoverflow} - /> - </> - <> - <DisplaySocial - base="https://codesandbox.com" - icon={icon_base_url + 'codesandbox.svg'} - username={props.social.codesandbox} - /> - </> - <> - <DisplaySocial base="https://kaggle.com" icon={icon_base_url + 'kaggle.svg'} username={props.social.kaggle} /> - </> - <> - <DisplaySocial base="https://fb.com" icon={icon_base_url + 'facebook.svg'} username={props.social.fb} /> - </> - <> - <DisplaySocial - base="https://instagram.com" - icon={icon_base_url + 'instagram.svg'} - username={props.social.instagram} - /> - </> - <> - <DisplaySocial - base="https://dribbble.com" - icon={icon_base_url + 'dribbble.svg'} - username={props.social.dribbble} - /> - </> - <> - <DisplaySocial - base="https://www.behance.net" - icon={icon_base_url + 'behance.svg'} - username={props.social.behance} - /> - </> - <> - <DisplaySocial base="https://medium.com" icon={icon_base_url + 'medium.svg'} username={props.social.medium} /> - </> - <> - <DisplaySocial - base="https://www.youtube.com/c" - icon={icon_base_url + 'youtube.svg'} - username={props.social.youtube} - /> - </> - <> - <DisplaySocial - base="https://www.codechef.com/users" - icon="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codechef.svg" - username={props.social.codechef} - /> - </> - <> - <DisplaySocial - base="https://www.hackerrank.com" - icon={icon_base_url + 'hackerrank.svg'} - username={props.social.hackerrank} - /> - </> - <> - <DisplaySocial - base="https://codeforces.com/profile" - icon={icon_base_url + 'codeforces.svg'} - username={props.social.codeforces} - /> - </> - <> - <DisplaySocial - base="https://www.leetcode.com" - icon={icon_base_url + 'leet-code.svg'} - username={props.social.leetcode} - /> - </> - <> - <DisplaySocial - base="https://www.hackerearth.com" - icon={icon_base_url + 'hackerearth.svg'} - username={props.social.hackerearth} - /> - </> - <> - <DisplaySocial - base="https://auth.geeksforgeeks.org/user" - icon={icon_base_url + 'geeks-for-geeks.svg'} - username={props.social.geeks_for_geeks} - /> - </> - <> - <DisplaySocial - base="https://www.topcoder.com/members" - icon={icon_base_url + 'topcoder.svg'} - username={props.social.topcoder} - /> - </> - <> - <DisplaySocial base="https://discord.gg" icon={icon_base_url + 'discord.svg'} username={props.social.discord} /> - </> - <> - <DisplaySocial base="" icon={icon_base_url + 'rss.svg'} username={props.social.rssurl} /> - </> - {isSocial(props.social) ? ( - <> - {`</p>`} - <br /> - <br /> - </> - ) : ( - '' - )} - <> - <DisplaySkills skills={props.skills} /> - </> - <> - <DisplaySupport support={props.support} /> - </> - <> - <DisplayTopLanguages - show={props.data.topLanguages} - showStats={props.data.githubStats} - github={props.social.github} - options={props.data.topLanguagesOptions} - /> - </> - <> - <GitHubStats - show={props.data.githubStats} - github={props.social.github} - options={props.data.githubStatsOptions} - /> - </> - <> - <DisplayStreakStats - show={props.data.streakStats} - github={props.social.github} - options={props.data.streakStatsOptions} - /> - </> - </div> - ); -}; -export default Markdown; diff --git a/src/components/markdown.jsx b/src/components/markdown.jsx new file mode 100644 index 00000000..27a4501c --- /dev/null +++ b/src/components/markdown.jsx @@ -0,0 +1,685 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { isMediumUsernameValid } from '../utils/validation'; +import { icons, skills as SKILLS, skillWebsites } from '../constants/skills'; +import { githubStatsLinkGenerator, topLanguagesLinkGenerator, streakStatsLinkGenerator } from '../utils/link-generators'; +import { DEFAULT_DATA, DEFAULT_LINK, DEFAULT_PREFIX, DEFAULT_SOCIAL, DEFAULT_SUPPORT } from '../constants/defaults'; + +const Title = (props) => { + const { prefix, title } = props; + if (prefix && title) { + return ( + <> + {`<h1 align="center">${`${prefix} ${title}`}</h1>`} + <br /> + </> + ); + } + return ''; +}; + +Title.propTypes = { + prefix: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, +}; + +const SubTitle = (props) => { + const { subtitle } = props; + if (subtitle) { + return ( + <> + {`<h3 align="center">${subtitle}</h3>`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +SubTitle.propTypes = { + subtitle: PropTypes.string.isRequired, +}; + +const SectionTitle = (props) => { + const { label } = props; + if (label) { + return ( + <> + {`<h3 align="left">${label}</h3>`} + <br /> + </> + ); + } + return ''; +}; + +SectionTitle.propTypes = { + label: PropTypes.string.isRequired, +}; + +const DisplayWork = (props) => { + const { prefix, project, link } = props; + if (prefix && project) { + if (link) { + return ( + <> + {`- ${prefix} [${project}](${link})`} + <br /> + <br /> + </> + ); + } + return ( + <> + {`- ${prefix} **${project}**`} + <br /> + <br /> + </> + ); + } + if (prefix && link) { + return ( + <> + {`- ${prefix} [${link}](${link})`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +DisplayWork.defaultProps = { + prefix: '', + project: '', + link: '', +}; + +DisplayWork.propTypes = { + prefix: PropTypes.string, + project: PropTypes.string, + link: PropTypes.string, +}; + +const DisplaySocial = (props) => { + const { username, base, icon } = props; + if (username) { + return ( + <> + {`<a href="${base}/${username}" target="blank"><img align="center" src="${icon}" alt="${username}" height="30" width="40" /></a>`} + <br /> + </> + ); + } + return ''; +}; + +DisplaySocial.propTypes = { + username: PropTypes.string.isRequired, + base: PropTypes.string.isRequired, + icon: PropTypes.string.isRequired, +}; + +const VisitorsBadge = (props) => { + const { github, badgeOptions, show } = props; + const link = `https://komarev.com/ghpvc/?username=${github}&label=${badgeOptions.badgeLabel}&color=${badgeOptions.badgeColor}&style=${badgeOptions.badgeStyle}`; + if (show) { + return ( + <> + {`<p align="left"> <img src="${link}" alt="${github}" /> </p>`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +VisitorsBadge.defaultProps = { + badgeOptions: { + badgeLabel: '', + badgeColor: '', + badgeStyle: '', + }, +}; + +VisitorsBadge.propTypes = { + github: PropTypes.string.isRequired, + badgeOptions: { + badgeLabel: PropTypes.string.isRequired, + badgeColor: PropTypes.string.isRequired, + badgeStyle: PropTypes.string.isRequired, + }, + show: PropTypes.bool.isRequired, +}; + +const TwitterBadge = (props) => { + const { twitter, show, base } = props; + const link = `https://img.shields.io/twitter/follow/${twitter}?logo=twitter&style=for-the-badge`; + if (show) { + return ( + <> + {`<p align="left"> <a href="${base}/${twitter}" target="blank"><img src="${link}" alt="${twitter}" /></a> </p>`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +TwitterBadge.propTypes = { + twitter: PropTypes.string.isRequired, + base: PropTypes.string.isRequired, + show: PropTypes.bool.isRequired, +}; + +const GithubProfileTrophy = (props) => { + const { show, github } = props; + const link = `https://github-profile-trophy.vercel.app/?username=${github}`; + if (show) { + return ( + <> + {`<p align="left"> <a href="https://github.com/ryo-ma/github-profile-trophy"><img src="${link}" alt="${github}" /></a> </p>`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +GithubProfileTrophy.propTypes = { + github: PropTypes.string.isRequired, + show: PropTypes.bool.isRequired, +}; + +const GitHubStats = (props) => { + const { show, github, options } = props; + if (show) { + return ( + <> + {`<p> <img align="center" src="${githubStatsLinkGenerator({ + github, + options, + })}" alt="${github}" /></p>`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +GitHubStats.defaultProps = { + options: { + theme: '', + titleColor: '', + textColor: '', + bgColor: '', + hideBorder: '', + cacheSeconds: 0, + locale: '', + }, +}; + +GitHubStats.propTypes = { + github: PropTypes.string.isRequired, + options: { + theme: PropTypes.string, + titleColor: PropTypes.string, + textColor: PropTypes.string, + bgColor: PropTypes.string, + hideBorder: PropTypes.string, + cacheSeconds: PropTypes.number, + locale: PropTypes.string, + }, + show: PropTypes.bool.isRequired, +}; + +const isSocial = (social) => { + let status = false; + const SOCIAL_KEYS = Object.keys(DEFAULT_SOCIAL); + Object.keys(social).forEach((key) => { + if (SOCIAL_KEYS.includes(key)) { + status = true; + } + }); + return status; +}; + +const DisplaySkills = (props) => { + const { skills } = props; + const listChosenSkills = []; + SKILLS.forEach((skill) => { + if (skills[skill]) { + listChosenSkills.push( + ` + <a href="${skillWebsites[skill]}" target="_blank" rel="noreferrer"> + <img src="${icons[skill]}" alt="${skill}" width="40" height="40"/> + </a> + `, + ); + } + }); + return listChosenSkills.length > 0 ? ( + <> + <SectionTitle label="Languages and Tools:" /> + {`<p align="left">${listChosenSkills.join(' ')}</p>`} + <br /> + <br /> + </> + ) : ( + '' + ); +}; + +DisplaySkills.defaultProps = { + skills: [], +}; + +DisplaySkills.propTypes = { + skills: [], +}; + +const DisplayDynamicBlogs = (props) => { + const { show } = props; + if (show) { + return ( + <> + ### Blogs posts + <br /> + {'<!-- BLOG-POST-LIST:START -->'} + <br /> + {'<!-- BLOG-POST-LIST:END -->'} + <br /> + <br /> + </> + ); + } + return ''; +}; + +DisplayDynamicBlogs.defaultProps = { + show: false, +}; + +DisplayDynamicBlogs.propTypes = { + show: PropTypes.bool, +}; + +const DisplayTopLanguages = (props) => { + const { show, showStats, github, options } = props; + if (show) { + if (!showStats) { + return ( + <> + {`<p><img align="center" src="${topLanguagesLinkGenerator({ + github, + options, + })}" alt="${github}" /></p>`} + <br /> + <br /> + </> + ); + } + return ( + <> + {`<p><img align="left" src="${topLanguagesLinkGenerator({ + github, + options, + })}" alt="${github}" /></p>`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +DisplayTopLanguages.defaultProps = { + options: { + theme: '', + titleColor: '', + textColor: '', + bgColor: '', + hideBorder: '', + cacheSeconds: '', + locale: '', + }, +}; + +DisplayTopLanguages.propTypes = { + github: PropTypes.string.isRequired, + options: { + theme: PropTypes.string, + titleColor: PropTypes.string, + textColor: PropTypes.string, + bgColor: PropTypes.string, + hideBorder: PropTypes.string, + cacheSeconds: PropTypes.number, + locale: PropTypes.string, + }, + show: PropTypes.bool.isRequired, + showStats: PropTypes.bool.isRequired, +}; + +const DisplayStreakStats = (props) => { + const { show, github, options } = props; + if (show) { + return ( + <> + {`<p><img align="center" src="${streakStatsLinkGenerator({ + github, + options, + })}" alt="${github}" /></p>`} + <br /> + <br /> + </> + ); + } + return ''; +}; + +DisplayStreakStats.defaultProps = { + options: { + theme: '', + titleColor: '', + textColor: '', + bgColor: '', + hideBorder: '', + cacheSeconds: '', + locale: '', + }, +}; + +DisplayStreakStats.propTypes = { + github: PropTypes.string.isRequired, + options: { + theme: PropTypes.string, + titleColor: PropTypes.string, + textColor: PropTypes.string, + bgColor: PropTypes.string, + hideBorder: PropTypes.string, + cacheSeconds: PropTypes.number, + locale: PropTypes.string, + }, + show: PropTypes.bool.isRequired, +}; + +const DisplaySupport = (props) => { + const { support } = props; + let viewSupport = false; + Object.keys(support).forEach((key) => { + if (support[key]) { + viewSupport = true; + } + }); + return viewSupport ? ( + <div> + <SectionTitle label="Support:" /> + {'<p>'} + {support.buyMeACoffee && + `<a href="https://www.buymeacoffee.com/${support.buyMeACoffee}"> + <img align="left" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" height="50" width="210" alt="${support.buyMeACoffee}" /></a>`} + {support.buyMeAKofi && + `<a href="https://ko-fi.com/${support.buyMeAKofi}"> + <img align="left" src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height="50" width="210" alt="${support.buyMeAKofi}" /></a>`} + {'</p><br><br>'} + <br /> + <br /> + </div> + ) : ( + '' + ); +}; + +DisplaySupport.defaultProps = { + support: { + buyMeACoffee: '', + buyMeAKofi: '', + }, +}; + +DisplaySupport.propTypes = { + support: { + buyMeACoffee: PropTypes.string, + buyMeAKofi: PropTypes.string, + }, +}; + +const Markdown = (props) => { + const { prefix, data, link, social, skills, support } = props; + const iconBaseUrl = 'https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/icons/Social/'; + return ( + <div id="markdown-content" className="break-words"> + <> + <Title prefix={prefix.title} title={data.title} /> + </> + <> + <SubTitle subtitle={data.subtitle} /> + </> + <> + <VisitorsBadge + show={data.visitorsBadge} + github={social.github} + badgeOptions={{ + badgeLabel: encodeURI(data.badgeLabel), + badgeColor: data.badgeColor, + badgeStyle: data.badgeStyle, + }} + /> + </> + <> + <GithubProfileTrophy show={data.githubProfileTrophy} github={social.github} /> + <TwitterBadge base="https://twitter.com" show={data.twitterBadge} twitter={social.twitter} /> + </> + <> + <DisplayWork prefix={prefix.currentWork} project={data.currentWork} link={link.currentWork} /> + </> + <> + <DisplayWork prefix={prefix.currentLearn} project={data.currentLearn} /> + </> + <> + <DisplayWork prefix={prefix.collaborateOn} project={data.collaborateOn} link={link.collaborateOn} /> + </> + <> + <DisplayWork prefix={prefix.helpWith} project={data.helpWith} link={link.helpWith} /> + </> + <> + <DisplayWork prefix={prefix.portfolio} link={link.portfolio} /> + </> + <> + <DisplayWork prefix={prefix.blog} link={link.blog} /> + </> + <> + <DisplayWork prefix={prefix.ama} project={data.ama} /> + </> + <> + <DisplayWork prefix={prefix.contact} project={data.contact} /> + </> + <> + <DisplayWork prefix={prefix.resume} link={link.resume} /> + </> + <> + <DisplayWork prefix={prefix.funFact} project={data.funFact} /> + </> + <> + <DisplayDynamicBlogs show={(data.devDynamicBlogs && social.dev) || (data.rssDynamicBlogs && social.rssurl) || (data.mediumDynamicBlogs && social.medium && isMediumUsernameValid(social.medium))} /> + </> + {isSocial(social) ? ( + <> + <SectionTitle label="Connect with me:" /> + {'<p align="left">'} + </> + ) : ( + '' + )} + <br /> + <> + <DisplaySocial base="https://codepen.io" icon={`${iconBaseUrl}codepen.svg`} username={social.codepen} /> + </> + <> + <DisplaySocial base="https://dev.to" icon={`${iconBaseUrl}devto.svg`} username={social.dev} /> + </> + <> + <DisplaySocial base="https://twitter.com" icon={`${iconBaseUrl}twitter.svg`} username={social.twitter} /> + </> + <> + <DisplaySocial base="https://linkedin.com/in" icon={`${iconBaseUrl}linked-in-alt.svg`} username={social.linkedin} /> + </> + <> + <DisplaySocial base="https://stackoverflow.com/users" icon={`${iconBaseUrl}stack-overflow.svg`} username={social.stackoverflow} /> + </> + <> + <DisplaySocial base="https://codesandbox.com" icon={`${iconBaseUrl}codesandbox.svg`} username={social.codesandbox} /> + </> + <> + <DisplaySocial base="https://kaggle.com" icon={`${iconBaseUrl}kaggle.svg`} username={social.kaggle} /> + </> + <> + <DisplaySocial base="https://fb.com" icon={`${iconBaseUrl}facebook.svg`} username={social.fb} /> + </> + <> + <DisplaySocial base="https://instagram.com" icon={`${iconBaseUrl}instagram.svg`} username={social.instagram} /> + </> + <> + <DisplaySocial base="https://dribbble.com" icon={`${iconBaseUrl}dribbble.svg`} username={social.dribbble} /> + </> + <> + <DisplaySocial base="https://www.behance.net" icon={`${iconBaseUrl}behance.svg`} username={social.behance} /> + </> + <> + <DisplaySocial base="https://medium.com" icon={`${iconBaseUrl}medium.svg`} username={social.medium} /> + </> + <> + <DisplaySocial base="https://www.youtube.com/c" icon={`${iconBaseUrl}youtube.svg`} username={social.youtube} /> + </> + <> + <DisplaySocial base="https://www.codechef.com/users" icon="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codechef.svg" username={social.codechef} /> + </> + <> + <DisplaySocial base="https://www.hackerrank.com" icon={`${iconBaseUrl}hackerrank.svg`} username={social.hackerrank} /> + </> + <> + <DisplaySocial base="https://codeforces.com/profile" icon={`${iconBaseUrl}codeforces.svg`} username={social.codeforces} /> + </> + <> + <DisplaySocial base="https://www.leetcode.com" icon={`${iconBaseUrl}leet-code.svg`} username={social.leetcode} /> + </> + <> + <DisplaySocial base="https://www.hackerearth.com" icon={`${iconBaseUrl}hackerearth.svg`} username={social.hackerearth} /> + </> + <> + <DisplaySocial base="https://auth.geeksforgeeks.org/user" icon={`${iconBaseUrl}geeks-for-geeks.svg`} username={social.geeks_for_geeks} /> + </> + <> + <DisplaySocial base="https://www.topcoder.com/members" icon={`${iconBaseUrl}topcoder.svg`} username={social.topcoder} /> + </> + <> + <DisplaySocial base="https://discord.gg" icon={`${iconBaseUrl}discord.svg`} username={social.discord} /> + </> + <> + <DisplaySocial base="" icon={`${iconBaseUrl}rss.svg`} username={social.rssurl} /> + </> + {isSocial(social) ? ( + <> + {'</p>'} + <br /> + <br /> + </> + ) : ( + '' + )} + <> + <DisplaySkills skills={skills} /> + </> + <> + <DisplaySupport support={support} /> + </> + <> + <DisplayTopLanguages show={data.topLanguages} showStats={data.githubStats} github={social.github} options={data.topLanguagesOptions} /> + </> + <> + <GitHubStats show={data.githubStats} github={social.github} options={data.githubStatsOptions} /> + </> + <> + <DisplayStreakStats show={data.streakStats} github={social.github} options={data.streakStatsOptions} /> + </> + </div> + ); +}; +export default Markdown; + +Markdown.defaultProps = { + prefix: DEFAULT_PREFIX, + data: DEFAULT_DATA, + link: DEFAULT_LINK, + social: DEFAULT_SOCIAL, + support: DEFAULT_SUPPORT, + skills: [], +}; +Markdown.propTypes = { + prefix: { + title: PropTypes.string, + currentWork: PropTypes.string, + currentLearn: PropTypes.string, + collaborateOn: PropTypes.string, + helpWith: PropTypes.string, + ama: PropTypes.string, + contact: PropTypes.string, + resume: PropTypes.string, + funFact: PropTypes.string, + portfolio: PropTypes.string, + blog: PropTypes.string, + }, + data: { + title: PropTypes.string, + subtitle: PropTypes.string, + currentWork: PropTypes.string, + currentLearn: PropTypes.string, + collaborateOn: PropTypes.string, + helpWith: PropTypes.string, + ama: PropTypes.string, + contact: PropTypes.string, + funFact: PropTypes.string, + twitterBadge: false, + visitorsBadge: false, + badgeStyle: PropTypes.string, + badgeColor: PropTypes.string, + badgeLabel: PropTypes.string, + githubProfileTrophy: false, + githubStats: false, + githubStatsOptions: { + theme: PropTypes.string, + titleColor: PropTypes.string, + textColor: PropTypes.string, + bgColor: PropTypes.string, + hideBorder: false, + cacheSeconds: null, + locale: PropTypes.string, + }, + topLanguages: false, + topLanguagesOptions: { + theme: PropTypes.string, + titleColor: PropTypes.string, + textColor: PropTypes.string, + bgColor: PropTypes.string, + hideBorder: false, + cacheSeconds: null, + locale: PropTypes.string, + }, + streakStats: false, + streakStatsOptions: { + theme: PropTypes.string, + }, + devDynamicBlogs: false, + mediumDynamicBlogs: false, + rssDynamicBlogs: false, + }, + link: {}, + social: {}, + skills: {}, + support: {}, +}; diff --git a/src/components/markdownPreview.js b/src/components/markdownPreview.js deleted file mode 100644 index 9bca18ab..00000000 --- a/src/components/markdownPreview.js +++ /dev/null @@ -1,412 +0,0 @@ -import React from 'react'; -import { icons, skills, skillWebsites } from '../constants/skills'; -import { - githubStatsLinkGenerator, - topLanguagesLinkGenerator, - streakStatsLinkGenerator, -} from '../utils/link-generators'; - -export const TitlePreview = (props) => { - if (props.prefix && props.title) { - return <h1 className="text-center text-xl font-bold">{props.prefix + ' ' + props.title}</h1>; - } - return null; -}; - -export const SubTitlePreview = (props) => { - if (props.subtitle) { - return <h3 className="text-center font-medium">{props.subtitle}</h3>; - } - return null; -}; - -export const SectionTitle = (props) => { - if (!props.visible) return null; - else if (props.label) { - return <h3 className="w-full text-lg sm:text-xl">{props.label}</h3>; - } - return null; -}; - -export const DisplayWork = (props) => { - if (props.prefix && props.project) { - if (props.link) { - return ( - <div className="my-2"> - {props.prefix + ' '} - <a href={props.link} className="no-underline text-blue-700" target="blank"> - {props.project} - </a> - </div> - ); - } else { - return ( - <div className="my-2"> - {props.prefix + ' '} - <b>{props.project}</b> - </div> - ); - } - } - if (props.prefix && props.link) { - return ( - <div className="my-2"> - {props.prefix + ' '} - <a href={props.link} className="no-underline text-blue-700" target="blank"> - {props.link} - </a> - </div> - ); - } - return null; -}; - -export const WorkPreview = (props) => { - const prefix = props.work.prefix; - const data = props.work.data; - const link = props.work.link; - return ( - <> - <DisplayWork prefix={prefix.currentWork} project={data.currentWork} link={link.currentWork} /> - <DisplayWork prefix={prefix.currentLearn} project={data.currentLearn} /> - <DisplayWork prefix={prefix.helpWith} project={data.helpWith} link={link.helpWith} /> - <DisplayWork prefix={prefix.collaborateOn} project={data.collaborateOn} link={link.collaborateOn} /> - <DisplayWork prefix={prefix.ama} project={data.ama} /> - <DisplayWork prefix={prefix.portfolio} link={link.portfolio} /> - <DisplayWork prefix={prefix.blog} link={link.blog} /> - <DisplayWork prefix={prefix.resume} link={link.resume} /> - <DisplayWork prefix={prefix.contact} project={data.contact} /> - <DisplayWork prefix={prefix.funFact} project={data.funFact} /> - </> - ); -}; - -export const DisplaySocial = (props) => { - if (props.username) { - return ( - <a className="no-underline text-blue-700 m-2" href={props.base + '/' + props.username} target="blank"> - <img className="w-6 h-6" src={props.icon} alt="props.username" /> - </a> - ); - } - return null; -}; - -export const SocialPreview = (props) => { - let viewSocial = false; - const icon_base_url = - 'https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/icons/Social/'; - Object.keys(props.social).forEach((key) => { - if (props.social[key] && key !== 'github') viewSocial = true; - }); - return ( - <div className="flex justify-start items-end flex-wrap"> - <SectionTitle label="Connect with me:" visible={viewSocial} /> - <> - <DisplaySocial base="https://codepen.io" icon={icon_base_url + 'codepen.svg'} username={props.social.codepen} /> - </> - <> - <DisplaySocial base="https://dev.to" icon={icon_base_url + 'devto.svg'} username={props.social.dev} /> - </> - <> - <DisplaySocial - base="https://twitter.com" - icon={icon_base_url + 'twitter.svg'} - username={props.social.twitter} - /> - </> - <> - <DisplaySocial - base="https://linkedin.com/in" - icon={icon_base_url + 'linked-in-alt.svg'} - username={props.social.linkedin} - /> - </> - <> - <DisplaySocial - base="https://stackoverflow.com/users" - icon={icon_base_url + 'stack-overflow.svg'} - username={props.social.stackoverflow} - /> - </> - <> - <DisplaySocial - base="https://codesandbox.com" - icon={icon_base_url + 'codesandbox.svg'} - username={props.social.codesandbox} - /> - </> - <> - <DisplaySocial base="https://kaggle.com" icon={icon_base_url + 'kaggle.svg'} username={props.social.kaggle} /> - </> - <> - <DisplaySocial base="https://fb.com" icon={icon_base_url + 'facebook.svg'} username={props.social.fb} /> - </> - <> - <DisplaySocial - base="https://instagram.com" - icon={icon_base_url + 'instagram.svg'} - username={props.social.instagram} - /> - </> - <> - <DisplaySocial - base="https://dribbble.com" - icon={icon_base_url + 'dribbble.svg'} - username={props.social.dribbble} - /> - </> - <> - <DisplaySocial - base="https://www.behance.net" - icon={icon_base_url + 'behance.svg'} - username={props.social.behance} - /> - </> - <> - <DisplaySocial base="https://medium.com" icon={icon_base_url + 'medium.svg'} username={props.social.medium} /> - </> - <> - <DisplaySocial - base="https://www.youtube.com/c" - icon={icon_base_url + 'youtube.svg'} - username={props.social.youtube} - /> - </> - <> - <DisplaySocial - base="https://www.codechef.com/users" - icon="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codechef.svg" - username={props.social.codechef} - /> - </> - <> - <DisplaySocial - base="https://www.hackerrank.com" - icon={icon_base_url + 'hackerrank.svg'} - username={props.social.hackerrank} - /> - </> - <> - <DisplaySocial - base="https://codeforces.com/profile" - icon={icon_base_url + 'codeforces.svg'} - username={props.social.codeforces} - /> - </> - <> - <DisplaySocial - base="https://www.leetcode.com" - icon={icon_base_url + 'leet-code.svg'} - username={props.social.leetcode} - /> - </> - <> - <DisplaySocial - base="https://www.hackerearth.com" - icon={icon_base_url + 'hackerearth.svg'} - username={props.social.hackerearth} - /> - </> - <> - <DisplaySocial - base="https://auth.geeksforgeeks.org/user" - icon={icon_base_url + 'geeks-for-geeks.svg'} - username={props.social.geeks_for_geeks} - /> - </> - <> - <DisplaySocial - base="https://www.topcoder.com/members" - icon={icon_base_url + 'topcoder.svg'} - username={props.social.topcoder} - /> - </> - <> - <DisplaySocial base="https://discord.gg" icon={icon_base_url + 'discord.svg'} username={props.social.discord} /> - </> - <> - <DisplaySocial base="" icon={icon_base_url + 'rss.svg'} username={props.social.rssurl} /> - </> - </div> - ); -}; - -export const VisitorsBadgePreview = (props) => { - let link = - 'https://komarev.com/ghpvc/?username=' + - props.github + - `&label=${props.badgeOptions.badgeLabel}` + - `&color=${props.badgeOptions.badgeColor}` + - `&style=${props.badgeOptions.badgeStyle}`; - if (props.show) { - return ( - <div className="text-left my-2"> - {' '} - <img className="h-4 sm:h-6" src={link} alt={props.github} />{' '} - </div> - ); - } - return null; -}; - -export 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" rel="noreferrer"> - <img className="h-4 sm:h-6" src={link} alt={props.twitter} /> - </a>{' '} - </div> - ); - } - return null; -}; - -export const GithubProfileTrophyPreview = (props) => { - let link = 'https://github-profile-trophy.vercel.app/?username=' + props.github; - if (props.show) { - return ( - <div className="text-left my-2"> - {' '} - <a href="https://github.com/ryo-ma/github-profile-trophy"> - <img src={link} alt={props.github} /> - </a>{' '} - </div> - ); - } - return null; -}; - -export const GitHubStatsPreview = ({ github, options, show }) => { - if (show) { - return ( - <div className="text-center mx-4 mb-4"> - <img src={githubStatsLinkGenerator({ github, options })} alt={github} /> - </div> - ); - } - return null; -}; - -export const TopLanguagesPreview = ({ github, options, show }) => { - if (show) { - return ( - <div className="text-center mx-4 mb-4"> - <img src={topLanguagesLinkGenerator({ github, options })} alt={github} /> - </div> - ); - } - return <div className="text-center mx-4 mb-4">  </div>; -}; - -export const StreakStatsPreview = ({ github, options, show }) => { - if (show) { - return ( - <div className="text-center mx-4 mb-4"> - <img src={streakStatsLinkGenerator({ github, options })} alt={github} /> - </div> - ); - } - return null; -}; - -export const SkillsPreview = (props) => { - var listSkills = []; - skills.forEach((skill) => { - if (props.skills[skill]) { - listSkills.push( - <a href={skillWebsites[skill]} key={skill} target="_blank" rel="noreferrer"> - <img className="mb-4 mr-4 h-6 w-6 sm:h-10 sm:w-10" src={icons[skill]} alt={skill} /> - </a> - ); - } - }); - return listSkills.length > 0 ? ( - <div className="flex flex-wrap justify-start items-center"> - <SectionTitle label="Languages and Tools:" visible={true} /> - {listSkills} - </div> - ) : ( - '' - ); -}; - -export const SupportPreview = (props) => { - let viewSupport = false; - Object.keys(props.support).forEach((key) => { - if (props.support[key]) { - viewSupport = true; - } - }); - return props.support.buyMeACoffee || props.support.buyMeAKofi ? ( - <div className="flex flex-wrap justify-start items-center"> - <SectionTitle label="Support:" visible={viewSupport} /> - {props.support.buyMeACoffee && ( - <a href={`https://www.buymeacoffee.com/` + props.support.buyMeACoffee} target="_blank" rel="noreferrer"> - <img - src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" - alt="Buy Me A Coffee" - className="mb-4 mr-4 w-36 h-8 sm:w-52 sm:h-12" - /> - </a> - )} - {props.support.buyMeAKofi && ( - <a href={`https://ko-fi.com/` + props.support.buyMeAKofi} target="_blank" rel="noreferrer"> - <img - src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" - alt="Buy Me A Ko-fi" - className="mb-4 mr-4 w-36 h-8 sm:w-52 sm:h-12" - /> - </a> - )} - </div> - ) : ( - '' - ); -}; - -const MarkdownPreview = (props) => { - return ( - <div id="markdown-preview"> - <TitlePreview prefix={props.prefix.title} title={props.data.title} /> - <SubTitlePreview subtitle={props.data.subtitle} /> - <VisitorsBadgePreview - show={props.data.visitorsBadge} - github={props.social.github} - badgeOptions={{ - badgeLabel: encodeURI(props.data.badgeLabel), - badgeColor: props.data.badgeColor, - badgeStyle: props.data.badgeStyle, - }} - /> - <GithubProfileTrophyPreview show={props.data.githubProfileTrophy} github={props.social.github} /> - <TwitterBadgePreview show={props.data.twitterBadge} twitter={props.social.twitter} /> - <WorkPreview work={props} /> - <SocialPreview social={props.social} /> - <SkillsPreview skills={props.skills} /> - <SupportPreview support={props.support} /> - <div className="block sm:flex sm:justify-center sm:items-start"> - <TopLanguagesPreview - show={props.data.topLanguages} - github={props.social.github} - options={props.data.topLanguagesOptions} - /> - <GitHubStatsPreview - show={props.data.githubStats} - github={props.social.github} - options={props.data.githubStatsOptions} - /> - <StreakStatsPreview - show={props.data.streakStats} - github={props.social.github} - options={props.data.streakStatsOptions} - /> - </div> - </div> - ); -}; - -export default MarkdownPreview; diff --git a/src/components/markdownPreview.jsx b/src/components/markdownPreview.jsx new file mode 100644 index 00000000..925e9c21 --- /dev/null +++ b/src/components/markdownPreview.jsx @@ -0,0 +1,454 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { icons, skills as SKILLS, skillWebsites } from '../constants/skills'; +import { githubStatsLinkGenerator, topLanguagesLinkGenerator, streakStatsLinkGenerator } from '../utils/link-generators'; +import { DEFAULT_DATA, DEFAULT_PREFIX, DEFAULT_SOCIAL, DEFAULT_SUPPORT } from '../constants/defaults'; + +export const TitlePreview = (props) => { + const { prefix, title } = props; + if (prefix && title) { + return <h1 className="text-center text-xl font-bold">{`${prefix} ${title}`}</h1>; + } + return null; +}; +TitlePreview.propTypes = { + prefix: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, +}; + +export const SubTitlePreview = (props) => { + const { subtitle } = props; + if (subtitle) { + return <h3 className="text-center font-medium">{subtitle}</h3>; + } + return null; +}; +SubTitlePreview.propTypes = { + subtitle: PropTypes.string.isRequired, +}; + +export const SectionTitle = (props) => { + const { visible, label } = props; + if (!visible) return null; + if (label) { + return <h3 className="w-full text-lg sm:text-xl">{label}</h3>; + } + return null; +}; +SectionTitle.defaultProps = { + visible: false, +}; +SectionTitle.propTypes = { + visible: PropTypes.bool, + label: PropTypes.string.isRequired, +}; + +export const DisplayWork = (props) => { + const { prefix, project, link } = props; + if (prefix && project) { + if (link) { + return ( + <div className="my-2"> + {`${prefix} `} + <a href={link} className="no-underline text-blue-700" target="blank"> + {project} + </a> + </div> + ); + } + return ( + <div className="my-2"> + {`${prefix} `} + <b>{project}</b> + </div> + ); + } + if (prefix && link) { + return ( + <div className="my-2"> + {`${prefix} `} + <a href={link} className="no-underline text-blue-700" target="blank"> + {link} + </a> + </div> + ); + } + return null; +}; + +DisplayWork.defaultProps = { + prefix: '', + project: '', + link: '', +}; + +DisplayWork.propTypes = { + prefix: PropTypes.string, + project: PropTypes.string, + link: PropTypes.string, +}; + +export const WorkPreview = (props) => { + const { work } = props; + const { prefix, data, link } = work; + return ( + <> + <DisplayWork prefix={prefix.currentWork} project={data.currentWork} link={link.currentWork} /> + <DisplayWork prefix={prefix.currentLearn} project={data.currentLearn} /> + <DisplayWork prefix={prefix.helpWith} project={data.helpWith} link={link.helpWith} /> + <DisplayWork prefix={prefix.collaborateOn} project={data.collaborateOn} link={link.collaborateOn} /> + <DisplayWork prefix={prefix.ama} project={data.ama} /> + <DisplayWork prefix={prefix.portfolio} link={link.portfolio} /> + <DisplayWork prefix={prefix.blog} link={link.blog} /> + <DisplayWork prefix={prefix.resume} link={link.resume} /> + <DisplayWork prefix={prefix.contact} project={data.contact} /> + <DisplayWork prefix={prefix.funFact} project={data.funFact} /> + </> + ); +}; +WorkPreview.propTypes = { + work: PropTypes.object.isRequired, +}; + +export const DisplaySocial = (props) => { + const { username, base, icon } = props; + if (username) { + return ( + <a className="no-underline text-blue-700 m-2" href={`${base}/${username}`} target="blank"> + <img className="w-6 h-6" src={icon} alt="username" /> + </a> + ); + } + return null; +}; +DisplaySocial.defaultProps = { + username: '', + base: '', + icon: '', +}; +DisplaySocial.propTypes = { + username: PropTypes.string, + base: PropTypes.string, + icon: PropTypes.string, +}; + +export const SocialPreview = (props) => { + const { social } = props; + let viewSocial = false; + const iconBaseUrl = 'https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/icons/Social/'; + Object.keys(social).forEach((key) => { + if (social[key] && key !== 'github') viewSocial = true; + }); + return ( + <div className="flex justify-start items-end flex-wrap"> + <SectionTitle label="Connect with me:" visible={viewSocial} /> + <> + <DisplaySocial base="https://codepen.io" icon={`${iconBaseUrl}codepen.svg`} username={social.codepen} /> + </> + <> + <DisplaySocial base="https://dev.to" icon={`${iconBaseUrl}devto.svg`} username={social.dev} /> + </> + <> + <DisplaySocial base="https://twitter.com" icon={`${iconBaseUrl}twitter.svg`} username={social.twitter} /> + </> + <> + <DisplaySocial base="https://linkedin.com/in" icon={`${iconBaseUrl}linked-in-alt.svg`} username={social.linkedin} /> + </> + <> + <DisplaySocial base="https://stackoverflow.com/users" icon={`${iconBaseUrl}stack-overflow.svg`} username={social.stackoverflow} /> + </> + <> + <DisplaySocial base="https://codesandbox.com" icon={`${iconBaseUrl}codesandbox.svg`} username={social.codesandbox} /> + </> + <> + <DisplaySocial base="https://kaggle.com" icon={`${iconBaseUrl}kaggle.svg`} username={social.kaggle} /> + </> + <> + <DisplaySocial base="https://fb.com" icon={`${iconBaseUrl}facebook.svg`} username={social.fb} /> + </> + <> + <DisplaySocial base="https://instagram.com" icon={`${iconBaseUrl}instagram.svg`} username={social.instagram} /> + </> + <> + <DisplaySocial base="https://dribbble.com" icon={`${iconBaseUrl}dribbble.svg`} username={social.dribbble} /> + </> + <> + <DisplaySocial base="https://www.behance.net" icon={`${iconBaseUrl}behance.svg`} username={social.behance} /> + </> + <> + <DisplaySocial base="https://medium.com" icon={`${iconBaseUrl}medium.svg`} username={social.medium} /> + </> + <> + <DisplaySocial base="https://www.youtube.com/c" icon={`${iconBaseUrl}youtube.svg`} username={social.youtube} /> + </> + <> + <DisplaySocial base="https://www.codechef.com/users" icon="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codechef.svg" username={social.codechef} /> + </> + <> + <DisplaySocial base="https://www.hackerrank.com" icon={`${iconBaseUrl}hackerrank.svg`} username={social.hackerrank} /> + </> + <> + <DisplaySocial base="https://codeforces.com/profile" icon={`${iconBaseUrl}codeforces.svg`} username={social.codeforces} /> + </> + <> + <DisplaySocial base="https://www.leetcode.com" icon={`${iconBaseUrl}leet-code.svg`} username={social.leetcode} /> + </> + <> + <DisplaySocial base="https://www.hackerearth.com" icon={`${iconBaseUrl}hackerearth.svg`} username={social.hackerearth} /> + </> + <> + <DisplaySocial base="https://auth.geeksforgeeks.org/user" icon={`${iconBaseUrl}geeks-for-geeks.svg`} username={social.geeks_for_geeks} /> + </> + <> + <DisplaySocial base="https://www.topcoder.com/members" icon={`${iconBaseUrl}topcoder.svg`} username={social.topcoder} /> + </> + <> + <DisplaySocial base="https://discord.gg" icon={`${iconBaseUrl}discord.svg`} username={social.discord} /> + </> + <> + <DisplaySocial base="" icon={`${iconBaseUrl}rss.svg`} username={social.rssurl} /> + </> + </div> + ); +}; +SocialPreview.propTypes = { + social: PropTypes.object.isRequired, +}; + +export const VisitorsBadgePreview = (props) => { + const { github, show, badgeOptions } = props; + const link = `https://komarev.com/ghpvc/?username=${github}&label=${badgeOptions.badgeLabel}&color=${badgeOptions.badgeColor}&style=${badgeOptions.badgeStyle}`; + if (show) { + return ( + <div className="text-left my-2"> + {' '} + <img className="h-4 sm:h-6" src={link} alt={github} />{' '} + </div> + ); + } + return null; +}; +VisitorsBadgePreview.defaultProps = { + github: '', + show: false, + badgeOptions: {}, +}; +VisitorsBadgePreview.propTypes = { + github: PropTypes.string, + show: PropTypes.bool, + badgeOptions: PropTypes.object, +}; + +export const TwitterBadgePreview = (props) => { + const { twitter, show } = props; + const link = `https://img.shields.io/twitter/follow/${twitter}?logo=twitter&style=for-the-badge`; + if (show) { + return ( + <div className="text-left my-2"> + {' '} + <a href={`https://twitter.com/${twitter}`} target="_blank" rel="noreferrer"> + <img className="h-4 sm:h-6" src={link} alt={twitter} /> + </a>{' '} + </div> + ); + } + return null; +}; +TwitterBadgePreview.defaultProps = { + twitter: '', + show: false, +}; +TwitterBadgePreview.propTypes = { + twitter: PropTypes.string, + show: PropTypes.bool, +}; + +export const GithubProfileTrophyPreview = (props) => { + const { github, show } = props; + const link = `https://github-profile-trophy.vercel.app/?username=${github}`; + if (show) { + return ( + <div className="text-left my-2"> + {' '} + <a href="https://github.com/ryo-ma/github-profile-trophy"> + <img src={link} alt={github} /> + </a>{' '} + </div> + ); + } + return null; +}; +GithubProfileTrophyPreview.defaultProps = { + github: '', + show: false, +}; +GithubProfileTrophyPreview.propTypes = { + github: PropTypes.string, + show: PropTypes.bool, +}; + +export const GitHubStatsPreview = ({ github, options, show }) => { + if (show) { + return ( + <div className="text-center mx-4 mb-4"> + <img src={githubStatsLinkGenerator({ github, options })} alt={github} /> + </div> + ); + } + return null; +}; +GitHubStatsPreview.defaultProps = { + github: '', + options: {}, + show: false, +}; +GitHubStatsPreview.propTypes = { + github: PropTypes.string, + options: PropTypes.object, + show: PropTypes.bool, +}; + +export const TopLanguagesPreview = ({ github, options, show }) => { + if (show) { + return ( + <div className="text-center mx-4 mb-4"> + <img src={topLanguagesLinkGenerator({ github, options })} alt={github} /> + </div> + ); + } + return <div className="text-center mx-4 mb-4">  </div>; +}; +TopLanguagesPreview.defaultProps = { + github: '', + options: {}, + show: false, +}; +TopLanguagesPreview.propTypes = { + github: PropTypes.string, + options: PropTypes.object, + show: PropTypes.bool, +}; + +export const StreakStatsPreview = ({ github, options, show }) => { + if (show) { + return ( + <div className="text-center mx-4 mb-4"> + <img src={streakStatsLinkGenerator({ github, options })} alt={github} /> + </div> + ); + } + return null; +}; +StreakStatsPreview.defaultProps = { + github: '', + options: {}, + show: false, +}; +StreakStatsPreview.propTypes = { + github: PropTypes.string, + options: PropTypes.object, + show: PropTypes.bool, +}; + +export const SkillsPreview = (props) => { + const { skills } = props; + const listSkills = []; + SKILLS.forEach((skill) => { + if (skills[skill]) { + listSkills.push( + <a href={skillWebsites[skill]} key={skill} target="_blank" rel="noreferrer"> + <img className="mb-4 mr-4 h-6 w-6 sm:h-10 sm:w-10" src={icons[skill]} alt={skill} /> + </a>, + ); + } + }); + return listSkills.length > 0 ? ( + <div className="flex flex-wrap justify-start items-center"> + <SectionTitle label="Languages and Tools:" visible /> + {listSkills} + </div> + ) : ( + '' + ); +}; +SkillsPreview.propTypes = { + skills: PropTypes.array.isRequired, +}; + +export const SupportPreview = (props) => { + const { support } = props; + let viewSupport = false; + Object.keys(support).forEach((key) => { + if (support[key]) { + viewSupport = true; + } + }); + return support.buyMeACoffee || support.buyMeAKofi ? ( + <div className="flex flex-wrap justify-start items-center"> + <SectionTitle label="Support:" visible={viewSupport} /> + {support.buyMeACoffee && ( + <a href={`https://www.buymeacoffee.com/${support.buyMeACoffee}`} target="_blank" rel="noreferrer"> + <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" className="mb-4 mr-4 w-36 h-8 sm:w-52 sm:h-12" /> + </a> + )} + {support.buyMeAKofi && ( + <a href={`https://ko-fi.com/${support.buyMeAKofi}`} target="_blank" rel="noreferrer"> + <img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" alt="Buy Me A Ko-fi" className="mb-4 mr-4 w-36 h-8 sm:w-52 sm:h-12" /> + </a> + )} + </div> + ) : ( + '' + ); +}; +SupportPreview.propTypes = { + support: PropTypes.object.isRequired, +}; + +const MarkdownPreview = (props) => { + const { prefix, data, social, skills, support } = props; + return ( + <div id="markdown-preview"> + <TitlePreview prefix={prefix.title} title={data.title} /> + <SubTitlePreview subtitle={data.subtitle} /> + <VisitorsBadgePreview + show={data.visitorsBadge} + github={social.github} + badgeOptions={{ + badgeLabel: encodeURI(data.badgeLabel), + badgeColor: data.badgeColor, + badgeStyle: data.badgeStyle, + }} + /> + <GithubProfileTrophyPreview show={data.githubProfileTrophy} github={social.github} /> + <TwitterBadgePreview show={data.twitterBadge} twitter={social.twitter} /> + <WorkPreview work={props} /> + <SocialPreview social={social} /> + <SkillsPreview skills={skills} /> + <SupportPreview support={support} /> + <div className="block sm:flex sm:justify-center sm:items-start"> + <TopLanguagesPreview show={data.topLanguages} github={social.github} options={data.topLanguagesOptions} /> + <GitHubStatsPreview show={data.githubStats} github={social.github} options={data.githubStatsOptions} /> + <StreakStatsPreview show={data.streakStats} github={social.github} options={data.streakStatsOptions} /> + </div> + </div> + ); +}; + +export default MarkdownPreview; + +MarkdownPreview.defaultProps = { + prefix: DEFAULT_PREFIX, + data: DEFAULT_DATA, + social: DEFAULT_SOCIAL, + support: DEFAULT_SUPPORT, + skills: [], +}; + +MarkdownPreview.propTypes = { + prefix: PropTypes.object, + data: PropTypes.object, + social: PropTypes.object, + skills: PropTypes.object, + support: PropTypes.object, +}; diff --git a/src/components/seo.js b/src/components/seo.jsx similarity index 99% rename from src/components/seo.js rename to src/components/seo.jsx index ea1290f9..0481b377 100644 --- a/src/components/seo.js +++ b/src/components/seo.jsx @@ -22,7 +22,7 @@ function SEO({ description, lang, meta, title }) { } } } - ` + `, ); const metaDescription = description || site.siteMetadata.description; diff --git a/src/components/skills.js b/src/components/skills.jsx similarity index 56% rename from src/components/skills.js rename to src/components/skills.jsx index 95bc2499..3e2cc953 100644 --- a/src/components/skills.js +++ b/src/components/skills.jsx @@ -1,29 +1,23 @@ import React, { useState } from 'react'; -import { icons, categorizedSkills } from '../constants/skills'; +import PropTypes from 'prop-types'; import { SearchIcon, XIcon } from '@primer/octicons-react'; +import { icons, categorizedSkills } from '../constants/skills'; const Skills = (props) => { + const { skills, handleSkillsChange } = props; const [search, setSearch] = useState(''); const [debounce, setDebounce] = useState(undefined); const inputRef = React.createRef(); - const createSkill = (skill) => { - return ( - <div className="w-1/3 sm:w-1/4 my-6" key={skill}> - <label htmlFor={skill} className="checkbox-label flex items-center justify-start"> - <input - id={skill} - type="checkbox" - className="checkbox-label__input" - checked={props.skills[skill]} - onChange={(event) => props.handleSkillsChange(skill)} - /> - <span class="checkbox-label__control" /> - <img className="ml-4 w-8 h-8 sm:w-10 sm:h-10" src={icons[skill]} alt={skill} /> - <span className="tooltiptext">{skill}</span> - </label> - </div> - ); - }; + const createSkill = (skill) => ( + <div className="w-1/3 sm:w-1/4 my-6" key={skill}> + <label htmlFor={skill} className="checkbox-label flex items-center justify-start"> + <input id={skill} type="checkbox" className="checkbox-label__input" checked={skills[skill]} onChange={() => handleSkillsChange(skill)} /> + <span className="checkbox-label__control" /> + <img className="ml-4 w-8 h-8 sm:w-10 sm:h-10" src={icons[skill]} alt={skill} /> + <span className="tooltiptext">{skill}</span> + </label> + </div> + ); const onSearchChange = (value) => { const callback = () => { @@ -38,16 +32,11 @@ const Skills = (props) => { <div className="text-xl sm:text-2xl font-bold font-title mt-2 mb-4 flex justify-between"> Skills <div className="relative flex"> - <input - type="text" - onChange={(e) => onSearchChange(e.target.value)} - className="leading:none text-xs my-0 py-1 px-2 pr-8 sm:text-xl border-2 border-gray-900 focus:border-blue-700 placeholder-gray-700" - placeholder="Search Skills" - ref={inputRef} - /> + <input type="text" onChange={(e) => onSearchChange(e.target.value)} className="leading:none text-xs my-0 py-1 px-2 pr-8 sm:text-xl border-2 border-gray-900 focus:border-blue-700 placeholder-gray-700" placeholder="Search Skills" ref={inputRef} /> <span className="absolute" style={{ right: '10px' }}> {search !== '' ? ( <button + type="button" className="focus:outline-none" onClick={() => { setSearch(''); @@ -65,28 +54,18 @@ const Skills = (props) => { {Object.keys(categorizedSkills) .filter((key) => { - let filtered = categorizedSkills[key].skills.filter((skill) => { - return skill.includes(search.toLowerCase()); - }); + const filtered = categorizedSkills[key].skills.filter((skill) => skill.includes(search.toLowerCase())); return filtered.length !== 0; }) .map((key) => ( <div key={key} className="divide-y divide-gray-500"> <div className="text-sm sm:text-xl text-gray-900 text-left py-1">{categorizedSkills[key].title}</div> - <div className="flex justify-start items-center flex-wrap w-full mb-6 pl-4 sm:pl-10"> - {categorizedSkills[key].skills - .filter((skill) => { - return skill.includes(search.toLowerCase()); - }) - .map((skill) => createSkill(skill))} - </div> + <div className="flex justify-start items-center flex-wrap w-full mb-6 pl-4 sm:pl-10">{categorizedSkills[key].skills.filter((skill) => skill.includes(search.toLowerCase())).map((skill) => createSkill(skill))}</div> </div> ))} <span className="flex justify-center text-gray-900"> {Object.keys(categorizedSkills).filter((key) => { - let filtered = categorizedSkills[key].skills.filter((skill) => { - return skill.includes(search.toLowerCase()); - }); + const filtered = categorizedSkills[key].skills.filter((skill) => skill.includes(search.toLowerCase())); return filtered.length !== 0; }).length === 0 ? 'No Results Found' @@ -97,3 +76,8 @@ const Skills = (props) => { }; export default Skills; + +Skills.propTypes = { + skills: PropTypes.array.isRequired, + handleSkillsChange: PropTypes.func.isRequired, +}; diff --git a/src/components/social.js b/src/components/social.js deleted file mode 100644 index 8f71f2f3..00000000 --- a/src/components/social.js +++ /dev/null @@ -1,335 +0,0 @@ -import React from 'react'; - -const Social = (props) => { - return ( - <div className="px-2 sm:px-6 mb-4"> - <div className="text-xl sm:text-2xl font-bold font-title mt-2 mb-2">Social</div> - <div className="flex flex-wrap justify-center items-center"> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/github.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="github" - /> - <input - id="github" - placeholder="github username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-1 sm:px-2 focus:border-blue-700" - value={props.social.github} - onChange={(event) => props.handleSocialChange('github', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@v3/icons/twitter.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="twitter" - /> - <input - id="twitter" - placeholder="twitter username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.twitter} - onChange={(event) => props.handleSocialChange('twitter', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/dev-dot-to.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="dev.to" - /> - <input - id="dev" - placeholder="dev.to username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.dev} - onChange={(event) => props.handleSocialChange('dev', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/codepen.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="codepen" - /> - <input - id="codepen" - placeholder="codepen username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.codepen} - onChange={(event) => props.handleSocialChange('codepen', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/codesandbox.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="codesandbox" - /> - <input - id="codesandbox" - placeholder="codesandbox username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.codesandbox} - onChange={(event) => props.handleSocialChange('codesandbox', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/stackoverflow.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="stackoverflow" - /> - <input - id="stackoverflow" - placeholder="stackoverflow user ID" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.stackoverflow} - onChange={(event) => props.handleSocialChange('stackoverflow', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/linkedin.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="linkedin" - /> - <input - id="linkedin" - placeholder="linkedin username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.linkedin} - onChange={(event) => props.handleSocialChange('linkedin', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/kaggle.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="kaggle" - /> - <input - id="kaggle" - placeholder="kaggle username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.kaggle} - onChange={(event) => props.handleSocialChange('kaggle', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/facebook.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="facebook" - /> - <input - id="fb" - placeholder="facebook username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.fb} - onChange={(event) => props.handleSocialChange('fb', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/instagram.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="instagram" - /> - <input - id="instagram" - placeholder="instagram username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.instagram} - onChange={(event) => props.handleSocialChange('instagram', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/dribbble.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="dribbble" - /> - <input - id="dribbble" - placeholder="dribbble username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.dribbble} - onChange={(event) => props.handleSocialChange('dribbble', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/behance.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="behance" - /> - <input - id="behance" - placeholder="behance username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.behance} - onChange={(event) => props.handleSocialChange('behance', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/medium.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="medium" - /> - <input - id="medium" - placeholder="medium username (with @)" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.medium} - onChange={(event) => props.handleSocialChange('medium', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/youtube.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="youtube" - /> - <input - id="youtube" - placeholder="youtube channel name" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.youtube} - onChange={(event) => props.handleSocialChange('youtube', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codechef.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="codechef" - /> - <input - id="codechef" - placeholder="codechef username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.codechef} - onChange={(event) => props.handleSocialChange('codechef', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/hackerrank.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="hackerrank" - /> - <input - id="hackerrank" - placeholder="hackerrank username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.hackerrank} - onChange={(event) => props.handleSocialChange('hackerrank', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codeforces.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="codeforces" - /> - <input - id="codeforces" - placeholder="codeforces username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.codeforces} - onChange={(event) => props.handleSocialChange('codeforces', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/leetcode.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="leetcode" - /> - <input - id="leetcode" - placeholder="leetcode username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.leetcode} - onChange={(event) => props.handleSocialChange('leetcode', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/topcoder.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="topcoder" - /> - <input - id="topcoder" - placeholder="topcoder username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.topcoder} - onChange={(event) => props.handleSocialChange('topcoder', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/hackerearth.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="hackerearth" - /> - <input - id="hackerearth" - placeholder="hackerearth user (with @)" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.hackerearth} - onChange={(event) => props.handleSocialChange('hackerearth', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/geeksforgeeks.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="geeksforgeeks" - /> - <input - id="geeksforgeeks" - placeholder="GFG (<username>/profile)" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.geeks_for_geeks} - onChange={(event) => props.handleSocialChange('geeks_for_geeks', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/discord.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="discord" - /> - <input - id="discord" - placeholder="discord invite (only code)" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.discord} - onChange={(event) => props.handleSocialChange('discord', event)} - /> - </div> - <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/rss.svg" - className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" - alt="rssfeed" - /> - <input - id="rssurl" - placeholder="RSS feed URL" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.social.rssurl} - onChange={(event) => props.handleSocialChange('rssurl', event)} - /> - </div> - </div> - </div> - ); -}; - -export default Social; diff --git a/src/components/social.jsx b/src/components/social.jsx new file mode 100644 index 00000000..8c32d8ef --- /dev/null +++ b/src/components/social.jsx @@ -0,0 +1,111 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Social = (props) => { + const { social, handleSocialChange } = props; + return ( + <div className="px-2 sm:px-6 mb-4"> + <div className="text-xl sm:text-2xl font-bold font-title mt-2 mb-2">Social</div> + <div className="flex flex-wrap justify-center items-center"> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/github.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="github" /> + <input id="github" placeholder="github username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-1 sm:px-2 focus:border-blue-700" value={social.github} onChange={(event) => handleSocialChange('github', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@v3/icons/twitter.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="twitter" /> + <input id="twitter" placeholder="twitter username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.twitter} onChange={(event) => handleSocialChange('twitter', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/dev-dot-to.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="dev.to" /> + <input id="dev" placeholder="dev.to username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.dev} onChange={(event) => handleSocialChange('dev', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/codepen.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="codepen" /> + <input id="codepen" placeholder="codepen username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.codepen} onChange={(event) => handleSocialChange('codepen', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/codesandbox.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="codesandbox" /> + <input id="codesandbox" placeholder="codesandbox username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.codesandbox} onChange={(event) => handleSocialChange('codesandbox', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/stackoverflow.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="stackoverflow" /> + <input id="stackoverflow" placeholder="stackoverflow user ID" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.stackoverflow} onChange={(event) => handleSocialChange('stackoverflow', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/linkedin.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="linkedin" /> + <input id="linkedin" placeholder="linkedin username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.linkedin} onChange={(event) => handleSocialChange('linkedin', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/kaggle.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="kaggle" /> + <input id="kaggle" placeholder="kaggle username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.kaggle} onChange={(event) => handleSocialChange('kaggle', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/facebook.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="facebook" /> + <input id="fb" placeholder="facebook username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.fb} onChange={(event) => handleSocialChange('fb', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/instagram.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="instagram" /> + <input id="instagram" placeholder="instagram username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.instagram} onChange={(event) => handleSocialChange('instagram', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/dribbble.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="dribbble" /> + <input id="dribbble" placeholder="dribbble username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.dribbble} onChange={(event) => handleSocialChange('dribbble', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/behance.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="behance" /> + <input id="behance" placeholder="behance username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.behance} onChange={(event) => handleSocialChange('behance', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/medium.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="medium" /> + <input id="medium" placeholder="medium username (with @)" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.medium} onChange={(event) => handleSocialChange('medium', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/youtube.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="youtube" /> + <input id="youtube" placeholder="youtube channel name" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.youtube} onChange={(event) => handleSocialChange('youtube', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codechef.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="codechef" /> + <input id="codechef" placeholder="codechef username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.codechef} onChange={(event) => handleSocialChange('codechef', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/hackerrank.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="hackerrank" /> + <input id="hackerrank" placeholder="hackerrank username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.hackerrank} onChange={(event) => handleSocialChange('hackerrank', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/codeforces.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="codeforces" /> + <input id="codeforces" placeholder="codeforces username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.codeforces} onChange={(event) => handleSocialChange('codeforces', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/leetcode.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="leetcode" /> + <input id="leetcode" placeholder="leetcode username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.leetcode} onChange={(event) => handleSocialChange('leetcode', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/topcoder.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="topcoder" /> + <input id="topcoder" placeholder="topcoder username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.topcoder} onChange={(event) => handleSocialChange('topcoder', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/hackerearth.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="hackerearth" /> + <input id="hackerearth" placeholder="hackerearth user (with @)" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.hackerearth} onChange={(event) => handleSocialChange('hackerearth', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/geeksforgeeks.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="geeksforgeeks" /> + <input id="geeksforgeeks" placeholder="GFG (<username>/profile)" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.geeks_for_geeks} onChange={(event) => handleSocialChange('geeks_for_geeks', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/discord.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="discord" /> + <input id="discord" placeholder="discord invite (only code)" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.discord} onChange={(event) => handleSocialChange('discord', event)} /> + </div> + <div className="w-1/2 flex justify-center items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.jsdelivr.net/npm/simple-icons@3.1.0/icons/rss.svg" className="w-6 h-6 sm:w-8 sm:h-8 mr-1 sm:mr-4" alt="rssfeed" /> + <input id="rssurl" placeholder="RSS feed URL" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={social.rssurl} onChange={(event) => handleSocialChange('rssurl', event)} /> + </div> + </div> + </div> + ); +}; + +export default Social; +Social.propTypes = { + social: PropTypes.object.isRequired, + handleSocialChange: PropTypes.func.isRequired, +}; diff --git a/src/components/subtitle.js b/src/components/subtitle.js deleted file mode 100644 index 15d8214d..00000000 --- a/src/components/subtitle.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; - -const Subtitle = (props) => { - return ( - <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">Subtitle</div> - <input - id="subtitle" - className="outline-none w-full text-xs sm:text-lg sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.data.subtitle} - onChange={(event) => props.handleDataChange('subtitle', event)} - /> - </div> - ); -}; - -export default Subtitle; diff --git a/src/components/subtitle.jsx b/src/components/subtitle.jsx new file mode 100644 index 00000000..841bae15 --- /dev/null +++ b/src/components/subtitle.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Subtitle = (props) => { + const { data, handleDataChange } = props; + return ( + <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">Subtitle</div> + <input id="subtitle" className="outline-none w-full text-xs sm:text-lg sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={data.subtitle} onChange={(event) => handleDataChange('subtitle', event)} /> + </div> + ); +}; + +export default Subtitle; +Subtitle.propTypes = { + data: PropTypes.object.isRequired, + handleDataChange: PropTypes.func.isRequired, +}; diff --git a/src/components/support.js b/src/components/support.js deleted file mode 100644 index 996d5157..00000000 --- a/src/components/support.js +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; - -const Support = (props) => { - return ( - <div className="px-2 sm:px-6 mb-4"> - <div className="text-xl sm:text-2xl font-bold font-title mt-2 mb-2">Support</div> - <div className="flex flex-wrap justify-start items-center"> - <div className="w-1/2 flex justify-start items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" - className="w-36 h-8 sm:w-52 sm:h-12 mr-1 sm:mr-4" - alt="buymeacoffee" - /> - <input - id="buy-me-a-coffee" - placeholder="buymeacoffee username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-1 focus:border-blue-700" - value={props.support.buyMeACoffee || ''} - onChange={(event) => props.handleSupportChange('buyMeACoffee', event)} - /> - </div> - <div className="w-1/2 flex justify-start items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> - <img - src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" - className="w-36 h-8 sm:w-52 sm:h-12 mr-1 sm:mr-4" - alt="buymeakofi" - /> - <input - id="buy-me-a-kofi" - placeholder="Ko-fi username" - className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-1 sm:px-2 ml-2 sm:ml-0 focus:border-blue-700" - value={props.support.buyMeAKofi || ''} - onChange={(event) => props.handleSupportChange('buyMeAKofi', event)} - /> - </div> - </div> - </div> - ); -}; - -export default Support; diff --git a/src/components/support.jsx b/src/components/support.jsx new file mode 100644 index 00000000..2f209b11 --- /dev/null +++ b/src/components/support.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Support = (props) => { + const { support, handleSupportChange } = props; + return ( + <div className="px-2 sm:px-6 mb-4"> + <div className="text-xl sm:text-2xl font-bold font-title mt-2 mb-2">Support</div> + <div className="flex flex-wrap justify-start items-center"> + <div className="w-1/2 flex justify-start items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" className="w-36 h-8 sm:w-52 sm:h-12 mr-1 sm:mr-4" alt="buymeacoffee" /> + <input id="buy-me-a-coffee" placeholder="buymeacoffee username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-1 focus:border-blue-700" value={support.buyMeACoffee || ''} onChange={(event) => handleSupportChange('buyMeACoffee', event)} /> + </div> + <div className="w-1/2 flex justify-start items-center text-xxs sm:text-lg py-4 pr-2 sm:pr-0"> + <img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" className="w-36 h-8 sm:w-52 sm:h-12 mr-1 sm:mr-4" alt="buymeakofi" /> + <input id="buy-me-a-kofi" placeholder="Ko-fi username" className="outline-none placeholder-gray-700 w-32 sm:w-1/2 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-1 sm:px-2 ml-2 sm:ml-0 focus:border-blue-700" value={support.buyMeAKofi || ''} onChange={(event) => handleSupportChange('buyMeAKofi', event)} /> + </div> + </div> + </div> + ); +}; + +export default Support; +Support.propTypes = { + support: PropTypes.object.isRequired, + handleSupportChange: PropTypes.func.isRequired, +}; diff --git a/src/components/title.js b/src/components/title.js deleted file mode 100644 index ab2852f5..00000000 --- a/src/components/title.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; - -const Title = (props) => { - return ( - <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 - id="title-prefix" - 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" - value={props.prefix.title} - onChange={(event) => props.handlePrefixChange('title', event)} - /> - <input - id="title-name" - placeholder="name" - 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" - value={props.data.title} - onChange={(event) => props.handleDataChange('title', event)} - /> - </div> - </div> - ); -}; - -export default Title; diff --git a/src/components/title.jsx b/src/components/title.jsx new file mode 100644 index 00000000..dbebb611 --- /dev/null +++ b/src/components/title.jsx @@ -0,0 +1,23 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Title = (props) => { + const { data, prefix, handlePrefixChange, handleDataChange } = props; + return ( + <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 id="title-prefix" 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" value={prefix.title} onChange={(event) => handlePrefixChange('title', event)} /> + <input id="title-name" placeholder="name" 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" value={data.title} onChange={(event) => handleDataChange('title', event)} /> + </div> + </div> + ); +}; + +export default Title; +Title.propTypes = { + prefix: PropTypes.object.isRequired, + data: PropTypes.object.isRequired, + handlePrefixChange: PropTypes.func.isRequired, + handleDataChange: PropTypes.func.isRequired, +}; diff --git a/src/components/work.js b/src/components/work.js deleted file mode 100644 index 839dfaea..00000000 --- a/src/components/work.js +++ /dev/null @@ -1,187 +0,0 @@ -import React from 'react'; - -const Work = (props) => { - return ( - <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">Work</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="currentWork-prefix" - placeholder="Hi, I'm " - className="outline-none placeholder-gray-700 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.currentWork} - onChange={(event) => props.handlePrefixChange('currentWork', event)} - /> - <input - id="currentWork" - placeholder="project name" - className="outline-none placeholder-gray-700 mr-8 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.data.currentWork} - onChange={(event) => props.handleDataChange('currentWork', event)} - /> - <input - id="currentWork-link" - placeholder="project link" - className="outline-none placeholder-gray-700 mr-8 sm:mr-0 text-blue-700 w-full sm:w-1/4 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.currentWork} - onChange={(event) => props.handleLinkChange('currentWork', 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"> - <input - id="collaborateOn-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.collaborateOn} - onChange={(event) => props.handlePrefixChange('collaborateOn', event)} - /> - <input - id="collaborateOn" - placeholder="project name" - className="outline-none placeholder-gray-700 mr-8 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.data.collaborateOn} - onChange={(event) => props.handleDataChange('collaborateOn', event)} - /> - <input - id="collaborateOn-link" - placeholder="project link" - className="outline-none placeholder-gray-700 mr-8 sm:mr-0 text-blue-700 w-full sm:w-1/4 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.collaborateOn} - onChange={(event) => props.handleLinkChange('collaborateOn', 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"> - <input - id="helpWith-prefix" - className="outline-none placeholder-gray-700 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.helpWith} - onChange={(event) => props.handlePrefixChange('helpWith', event)} - /> - <input - id="helpWith" - placeholder="project name" - className="outline-none placeholder-gray-700 mr-8 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" - value={props.data.helpWith} - onChange={(event) => props.handleDataChange('helpWith', event)} - /> - <input - id="helpWith-link" - placeholder="project link" - className="outline-none placeholder-gray-700 mr-8 sm:mr-0 text-blue-700 w-full sm:w-1/4 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.helpWith} - onChange={(event) => props.handleLinkChange('helpWith', 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"> - <input - id="currentLearn-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.currentLearn} - onChange={(event) => props.handlePrefixChange('currentLearn', event)} - /> - <input - id="currentLearn" - placeholder="Frameworks, courses etc." - className="outline-none placeholder-gray-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.data.currentLearn} - onChange={(event) => props.handleDataChange('currentLearn', 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"> - <input - id="ama-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.ama} - onChange={(event) => props.handlePrefixChange('ama', event)} - /> - <input - id="ama" - placeholder="react, vue and gsap" - className="outline-none placeholder-gray-700 mr-8 sm:mr-0 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.data.ama} - onChange={(event) => props.handleDataChange('ama', 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"> - <input - id="contact-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.contact} - onChange={(event) => props.handlePrefixChange('contact', event)} - /> - <input - id="contact" - placeholder="example@gmail.com" - className="outline-none placeholder-gray-700 mr-8 sm:mr-0 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.data.contact} - onChange={(event) => props.handleDataChange('contact', 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"> - <input - id="portfolio-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.portfolio} - onChange={(event) => props.handlePrefixChange('portfolio', event)} - /> - <input - id="portfolio" - placeholder="portfolio 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.portfolio} - onChange={(event) => props.handleLinkChange('portfolio', 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"> - <input - id="blog-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.blog} - onChange={(event) => props.handlePrefixChange('blog', event)} - /> - <input - id="blog" - placeholder="blog 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.blog} - onChange={(event) => props.handleLinkChange('blog', 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"> - <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"> - <input - id="funFact-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.funFact} - onChange={(event) => props.handlePrefixChange('funFact', event)} - /> - <input - id="funFact" - placeholder="I think I am funny" - className="outline-none placeholder-gray-700 mr-8 sm:mr-0 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.data.funFact} - onChange={(event) => props.handleDataChange('funFact', event)} - /> - </div> - </div> - ); -}; - -export default Work; diff --git a/src/components/work.jsx b/src/components/work.jsx new file mode 100644 index 00000000..662df846 --- /dev/null +++ b/src/components/work.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Work = (props) => { + const { prefix, handlePrefixChange, data, handleDataChange, link, handleLinkChange } = props; + return ( + <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">Work</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="currentWork-prefix" placeholder="Hi, I'm " className="outline-none placeholder-gray-700 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={prefix.currentWork} onChange={(event) => handlePrefixChange('currentWork', event)} /> + <input id="currentWork" placeholder="project name" className="outline-none placeholder-gray-700 mr-8 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={data.currentWork} onChange={(event) => handleDataChange('currentWork', event)} /> + <input id="currentWork-link" placeholder="project link" className="outline-none placeholder-gray-700 mr-8 sm:mr-0 text-blue-700 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={link.currentWork} onChange={(event) => handleLinkChange('currentWork', 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"> + <input id="collaborateOn-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={prefix.collaborateOn} onChange={(event) => handlePrefixChange('collaborateOn', event)} /> + <input id="collaborateOn" placeholder="project name" className="outline-none placeholder-gray-700 mr-8 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={data.collaborateOn} onChange={(event) => handleDataChange('collaborateOn', event)} /> + <input id="collaborateOn-link" placeholder="project link" className="outline-none placeholder-gray-700 mr-8 sm:mr-0 text-blue-700 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={link.collaborateOn} onChange={(event) => handleLinkChange('collaborateOn', 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"> + <input id="helpWith-prefix" className="outline-none placeholder-gray-700 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={prefix.helpWith} onChange={(event) => handlePrefixChange('helpWith', event)} /> + <input id="helpWith" placeholder="project name" className="outline-none placeholder-gray-700 mr-8 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={data.helpWith} onChange={(event) => handleDataChange('helpWith', event)} /> + <input id="helpWith-link" placeholder="project link" className="outline-none placeholder-gray-700 mr-8 sm:mr-0 text-blue-700 w-full sm:w-1/4 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700" value={link.helpWith} onChange={(event) => handleLinkChange('helpWith', 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"> + <input id="currentLearn-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={prefix.currentLearn} onChange={(event) => handlePrefixChange('currentLearn', event)} /> + <input id="currentLearn" placeholder="Frameworks, courses etc." className="outline-none placeholder-gray-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={data.currentLearn} onChange={(event) => handleDataChange('currentLearn', 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"> + <input id="ama-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={prefix.ama} onChange={(event) => handlePrefixChange('ama', event)} /> + <input id="ama" placeholder="react, vue and gsap" className="outline-none placeholder-gray-700 mr-8 sm:mr-0 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={data.ama} onChange={(event) => handleDataChange('ama', 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"> + <input id="contact-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={prefix.contact} onChange={(event) => handlePrefixChange('contact', event)} /> + <input id="contact" placeholder="example@gmail.com" className="outline-none placeholder-gray-700 mr-8 sm:mr-0 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={data.contact} onChange={(event) => handleDataChange('contact', 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"> + <input id="portfolio-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={prefix.portfolio} onChange={(event) => handlePrefixChange('portfolio', event)} /> + <input id="portfolio" placeholder="portfolio 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={link.portfolio} onChange={(event) => handleLinkChange('portfolio', 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"> + <input id="blog-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={prefix.blog} onChange={(event) => handlePrefixChange('blog', event)} /> + <input id="blog" placeholder="blog 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={link.blog} onChange={(event) => handleLinkChange('blog', 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"> + <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={prefix.resume} onChange={(event) => 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={link.resume} onChange={(event) => 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"> + <input id="funFact-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={prefix.funFact} onChange={(event) => handlePrefixChange('funFact', event)} /> + <input id="funFact" placeholder="I think I am funny" className="outline-none placeholder-gray-700 mr-8 sm:mr-0 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={data.funFact} onChange={(event) => handleDataChange('funFact', event)} /> + </div> + </div> + ); +}; + +export default Work; +Work.propTypes = { + prefix: PropTypes.object.isRequired, + data: PropTypes.object.isRequired, + link: PropTypes.object.isRequired, + handlePrefixChange: PropTypes.func.isRequired, + handleDataChange: PropTypes.func.isRequired, + handleLinkChange: PropTypes.func.isRequired, +}; diff --git a/src/pages/404.js b/src/pages/404.jsx similarity index 100% rename from src/pages/404.js rename to src/pages/404.jsx diff --git a/src/pages/index.js b/src/pages/index.jsx similarity index 63% rename from src/pages/index.js rename to src/pages/index.jsx index 62a6861c..2fc7f98b 100644 --- a/src/pages/index.js +++ b/src/pages/index.jsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import gsap from 'gsap'; +import { ArrowLeftIcon, CopyIcon, DownloadIcon, EyeIcon, CheckIcon, MarkdownIcon, FileCodeIcon } from '@primer/octicons-react'; import MarkdownPreview from '../components/markdownPreview'; import Markdown from '../components/markdown'; import Title from '../components/title'; @@ -15,15 +16,6 @@ import Loader from '../components/loader'; import SEO from '../components/seo'; import Layout from '../components/layout'; import './index.css'; -import { - ArrowLeftIcon, - CopyIcon, - DownloadIcon, - EyeIcon, - CheckIcon, - MarkdownIcon, - FileCodeIcon, -} from '@primer/octicons-react'; import { isGitHubUsernameValid, isMediumUsernameValid, isTwitterUsernameValid } from '../utils/validation'; import { DEFAULT_PREFIX, DEFAULT_DATA, DEFAULT_LINK, DEFAULT_SOCIAL, DEFAULT_SUPPORT } from '../constants/defaults'; @@ -38,7 +30,7 @@ const KeepCacheUpdated = ({ prefix, data, link, social, skills, support }) => { social, skills, support, - }) + }), ); }, [prefix, data, link, social, skills, support]); }; @@ -68,50 +60,50 @@ const IndexPage = () => { }); const handleSkillsChange = (field) => { - let change = { ...skills }; + const change = { ...skills }; change[field] = !change[field]; setSkills(change); }; const handlePrefixChange = (field, e) => { - let change = { ...prefix }; + const change = { ...prefix }; change[field] = e.target.value; setPrefix(change); }; const handleDataChange = (field, e) => { - let change = { ...data }; + const change = { ...data }; change[field] = e.target.value; setData(change); }; const handleLinkChange = (field, e) => { - let change = { ...link }; + const change = { ...link }; change[field] = e.target.value; setLink(change); }; const handleSocialChange = (field, e) => { - let change = { ...social }; + const change = { ...social }; change[field] = field === 'discord' ? e.target.value : e.target.value.toLowerCase(); setSocial(change); }; const handleSupportChange = (field, e) => { - let change = { ...support }; + const change = { ...support }; change[field] = e.target.value; setSupport(change); }; const handleCheckChange = (field) => { - let change = { ...data }; + const change = { ...data }; change[field] = !change[field]; setData(change); }; const generate = () => { setShowConfig(false); - var tl = new gsap.timeline(); + const tl = gsap.timeline(); tl.to('.generate', { scale: 0, duration: 0.5, @@ -131,7 +123,7 @@ const IndexPage = () => { scale: 1, duration: 0.5, ease: 'Linear.easeNone', - } + }, ); gsap.fromTo( '#support', @@ -142,7 +134,7 @@ const IndexPage = () => { autoAlpha: 1, duration: 2, ease: 'Linear.easeNone', - } + }, ); document.body.scrollTop = 0; // For Safari document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera @@ -151,10 +143,26 @@ const IndexPage = () => { const trimDataValues = (item, setItem) => { const dataObj = { ...item }; - Object.keys(dataObj).forEach((k) => (typeof dataObj[k] === 'string' ? (dataObj[k] = dataObj[k].trim()) : null)); + Object.keys(dataObj).forEach((k) => { + if (typeof dataObj[k] === 'string') { + dataObj[k] = dataObj[k].trim(); + } + }); setItem(dataObj); }; + const resetCopyMarkdownButton = () => { + const el = document.getElementById('copy-markdown'); + if (el) { + gsap.set('#copy-markdown', { + color: '#0a0a23', + }); + } + setcopyObj({ + isCopied: false, + copiedText: 'copy-markdown', + }); + }; const handleGenerate = () => { trimDataValues(data, setData); trimDataValues(social, setSocial); @@ -204,21 +212,8 @@ const IndexPage = () => { } }; - const resetCopyMarkdownButton = () => { - var el = document.getElementById('copy-markdown'); - if (el) { - gsap.set('#copy-markdown', { - color: '#0a0a23', - }); - } - setcopyObj({ - isCopied: false, - copiedText: 'copy-markdown', - }); - }; - const setCopyMarkdownButton = () => { - var el = document.getElementById('copy-markdown'); + const el = document.getElementById('copy-markdown'); if (el) { gsap.set('#copy-markdown', { color: '#00471b', @@ -234,7 +229,7 @@ const IndexPage = () => { ease: 'elastic.in', border: '2px solid #00471b', duration: 0.5, - } + }, ); setcopyObj({ isCopied: true, @@ -243,7 +238,7 @@ const IndexPage = () => { }; const handleCopyToClipboard = () => { - var range = document.createRange(); + const range = document.createRange(); range.selectNode(document.getElementById('markdown-content')); window.getSelection().removeAllRanges(); // clear current selection window.getSelection().addRange(range); // to select text @@ -254,12 +249,9 @@ const IndexPage = () => { }; const handleDownloadMarkdown = () => { - var markdownContent = document.getElementById('markdown-content'); - var tempElement = document.createElement('a'); - tempElement.setAttribute( - 'href', - 'data:text/markdown;charset=utf-8,' + encodeURIComponent(markdownContent.innerText) - ); + const markdownContent = document.getElementById('markdown-content'); + const tempElement = document.createElement('a'); + tempElement.setAttribute('href', `data:text/markdown;charset=utf-8,${encodeURIComponent(markdownContent.innerText)}`); tempElement.setAttribute('download', 'README.md'); tempElement.style.display = 'none'; document.body.appendChild(tempElement); @@ -268,13 +260,8 @@ const IndexPage = () => { }; const handleDownloadJson = () => { - var tempElement = document.createElement('a'); - tempElement.setAttribute( - 'href', - `data:text/json;charset=utf-8,${encodeURIComponent( - JSON.stringify({ prefix, data, link, social, skills, support }) - )}` - ); + const tempElement = document.createElement('a'); + tempElement.setAttribute('href', `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify({ prefix, data, link, social, skills, support }))}`); tempElement.setAttribute('download', 'data.json'); tempElement.style.display = 'none'; document.body.appendChild(tempElement); @@ -294,6 +281,20 @@ const IndexPage = () => { }); }; + const mergeDefaultWithNewDataSkills = (defaultSkills, newSkills) => + Object.keys(defaultSkills).reduce((previous, currentKey) => { + let currentSelected = false; + + if (newSkills[currentKey]) { + currentSelected = true; + } + + return { + ...previous, + [currentKey]: currentSelected, + }; + }, {}); + const setInitialValues = () => { const cache = JSON.parse(localStorage.getItem('cache')); @@ -322,7 +323,7 @@ const IndexPage = () => { boxShadow: '0 0 0 10px rgba(59, 59, 79, 0)', repeat: -1, duration: 1, - } + }, ); // set initial values @@ -341,21 +342,6 @@ const IndexPage = () => { setSupport(DEFAULT_SUPPORT); }; - const mergeDefaultWithNewDataSkills = (defaultSkills, newSkills) => { - return Object.keys(defaultSkills).reduce((previous, currentKey) => { - let currentSelected = false; - - if (newSkills[currentKey]) { - currentSelected = true; - } - - return { - ...previous, - [currentKey]: currentSelected, - }; - }, {}); - }; - const handleRestore = () => { try { const restoreData = JSON.parse(restore); @@ -373,6 +359,7 @@ const IndexPage = () => { const restoreDataSkills = mergeDefaultWithNewDataSkills(DEFAULT_SKILLS, restoreData.skills); setSkills(restoreDataSkills || DEFAULT_SKILLS); } catch (error) { + throw new Error(error); } finally { setRestore(''); } @@ -394,87 +381,25 @@ const IndexPage = () => { <div className="m-4 sm:p-4"> <SEO title="GitHub Profile Readme Generator" /> <div id="form"> - <Title - data={data} - prefix={prefix} - handleDataChange={handleDataChange} - handlePrefixChange={handlePrefixChange} - /> + <Title data={data} prefix={prefix} handleDataChange={handleDataChange} handlePrefixChange={handlePrefixChange} /> <Subtitle data={data} handleDataChange={handleDataChange} /> - <Work - prefix={prefix} - data={data} - link={link} - handlePrefixChange={handlePrefixChange} - handleLinkChange={handleLinkChange} - handleDataChange={handleDataChange} - /> + <Work prefix={prefix} data={data} link={link} handlePrefixChange={handlePrefixChange} handleLinkChange={handleLinkChange} handleDataChange={handleDataChange} /> <Skills skills={skills} handleSkillsChange={handleSkillsChange} /> <Social social={social} handleSocialChange={handleSocialChange} /> - <Addons - data={data} - social={social} - handleCheckChange={handleCheckChange} - handleDataChange={handleDataChange} - /> + <Addons data={data} social={social} handleCheckChange={handleCheckChange} handleDataChange={handleDataChange} /> <Support support={support} handleSupportChange={handleSupportChange} /> <div className="section"> - {(data.visitorsBadge || - data.githubProfileTrophy || - data.githubStats || - data.topLanguages || - data.streakStats) && - !social.github ? ( - <div className="warning">* Please add github username to use these add-ons</div> - ) : ( - '' - )} - {social.github && !isGitHubUsernameValid(social.github) ? ( - <div className="warning">* GitHub username is invalid, please add a valid username</div> - ) : ( - '' - )} - {social.medium && !isMediumUsernameValid(social.medium) ? ( - <div className="warning">* Medium username is invalid, please add a valid username (with @)</div> - ) : ( - '' - )} - {data.mediumDynamicBlogs && !social.medium ? ( - <div className="warning">* Please add medium username to display latest blogs dynamically</div> - ) : ( - '' - )} - {data.devDynamicBlogs && !social.dev ? ( - <div className="warning">* Please add dev.to username to display latest blogs dynamically</div> - ) : ( - '' - )} - {data.rssDynamicBlogs && !social.rssurl ? ( - <div className="warning"> - * Please add your rss feed url to display latest blogs dynamically from your personal blog - </div> - ) : ( - '' - )} - {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> - ) : ( - '' - )} + {(data.visitorsBadge || data.githubProfileTrophy || data.githubStats || data.topLanguages || data.streakStats) && !social.github ? <div className="warning">* Please add github username to use these add-ons</div> : ''} + {social.github && !isGitHubUsernameValid(social.github) ? <div className="warning">* GitHub username is invalid, please add a valid username</div> : ''} + {social.medium && !isMediumUsernameValid(social.medium) ? <div className="warning">* Medium username is invalid, please add a valid username (with @)</div> : ''} + {data.mediumDynamicBlogs && !social.medium ? <div className="warning">* Please add medium username to display latest blogs dynamically</div> : ''} + {data.devDynamicBlogs && !social.dev ? <div className="warning">* Please add dev.to username to display latest blogs dynamically</div> : ''} + {data.rssDynamicBlogs && !social.rssurl ? <div className="warning">* Please add your rss feed url to display latest blogs dynamically from your personal blog</div> : ''} + {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 className="flex items-center justify-center w-full"> - <div - className="text-xs sm:text-xl font-medium border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1 sm:py-2 px-2 sm:px-4 generate" - tabIndex="0" - role="button" - onClick={handleGenerate} - onKeyDown={(e) => e.keyCode === 13 && handleGenerate()} - > + <div className="text-xs sm:text-xl font-medium border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1 sm:py-2 px-2 sm:px-4 generate" tabIndex="0" role="button" onClick={handleGenerate} onKeyDown={(e) => e.keyCode === 13 && handleGenerate()}> Generate README </div> </div> @@ -485,51 +410,33 @@ const IndexPage = () => { {generateMarkdown || generatePreview ? ( <div className="markdown-section p-4 sm:py-4 sm:px-10"> <div className="w-full flex justify-between items-center"> - <button - className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" - onClick={handleBackToEdit} - > + <button type="button" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" onClick={handleBackToEdit}> <ArrowLeftIcon size={24} /> <span className="hidden sm:block"> back to edit</span> </button> - <button - className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" - id="copy-button" - onClick={handleCopyToClipboard} - > + <button type="button" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" id="copy-button" onClick={handleCopyToClipboard}> {copyObj.isCopied === true ? <CheckIcon size={24} /> : <CopyIcon size={24} />} <span className="hidden sm:block" id="copy-markdown"> {copyObj.copiedText} </span> </button> - <button - className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" - id="download-md-button" - onClick={handleDownloadMarkdown} - > + <button type="button" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" id="download-md-button" onClick={handleDownloadMarkdown}> <DownloadIcon size={24} /> <span className="hidden sm:block" id="download-markdown"> download markdown </span> </button> - <button - className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" - id="download-json-button" - onClick={handleDownloadJson} - > + <button type="button" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" id="download-json-button" onClick={handleDownloadJson}> <FileCodeIcon size={24} /> <span className="hidden sm:block" id="download-json"> download backup </span> </button> - <button - className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" - onClick={handleGeneratePreview} - > + <button type="button" className="text-base w-1/6 border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center p-1" onClick={handleGeneratePreview}> {previewMarkdown.isPreview ? <MarkdownIcon size={16} /> : <EyeIcon size={16} />} <span className="hidden sm:block ml-1" id="preview-markdown"> {previewMarkdown.buttonText} @@ -538,27 +445,9 @@ const IndexPage = () => { </div> <div className="w-full flex justify-center items-center"> - <div - className="w-full text-sm text-gray-900 shadow-xl mt-2 p-4 bg-gray-100 border-2 border-solid border-gray-800" - id="markdown-box" - > - {generatePreview ? ( - <MarkdownPreview - prefix={prefix} - data={data} - link={link} - social={social} - skills={skills} - support={support} - /> - ) : ( - '' - )} - {generateMarkdown ? ( - <Markdown prefix={prefix} data={data} link={link} social={social} skills={skills} support={support} /> - ) : ( - '' - )} + <div className="w-full text-sm text-gray-900 shadow-xl mt-2 p-4 bg-gray-100 border-2 border-solid border-gray-800" id="markdown-box"> + {generatePreview ? <MarkdownPreview prefix={prefix} data={data} link={link} social={social} skills={skills} support={support} /> : ''} + {generateMarkdown ? <Markdown prefix={prefix} data={data} link={link} social={social} skills={skills} support={support} /> : ''} </div> </div> <div className="mt-10" id="support"> @@ -568,49 +457,27 @@ const IndexPage = () => { ) : ( '' )} - <div - className={ - 'w-full shadow flex flex-col justify-center items-start mt-16 border-2 border-solid border-gray-600 py-2 px-4 ' + - (!showConfig ? 'hidden' : 'block') - } - > + <div className={`w-full shadow flex flex-col justify-center items-start mt-16 border-2 border-solid border-gray-600 py-2 px-4 ${!showConfig ? 'hidden' : 'block'}`}> <div className="flex justify-between items-center w-full"> <div className="text-lg sm:text-2xl font-bold font-title mt-2 mb-2"> Config options <span className="bg-green-800 text-white text-xs sm:text-sm p-1 ml-1">new feature</span> </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" - onClick={handleResetForm} - > + <button type="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" onClick={handleResetForm}> Reset form </button> </div> <div className="w-full flex justify-start items-center my-4"> - <input - type="text" - className="outline-none w-1/2 mr-6 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700 prefix" - placeholder="Paste JSON code or upload file" - value={restore} - onChange={(e) => setRestore(e.target.value)} - /> + <input type="text" className="outline-none w-1/2 mr-6 border-t-0 border-l-0 border-r-0 border solid border-gray-900 py-1 px-2 focus:border-blue-700 prefix" placeholder="Paste JSON code or upload file" value={restore} onChange={(e) => setRestore(e.target.value)} /> <div className="overflow-hidden relative w-64 mt-4 mb-4"> - <input - className="cursor-pointer absolute block opacity-0 pin-r pin-t before:cursor-pointer" - type="file" - name="vacancyImageFiles" - onChange={handleFileInput} - /> - <button className="text-xxs sm:text-sm border-2 w-40 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1"> + <input className="cursor-pointer absolute block opacity-0 pin-r pin-t before:cursor-pointer" type="file" name="vacancyImageFiles" onChange={handleFileInput} /> + <button type="button" className="text-xxs sm:text-sm border-2 w-40 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1"> Upload json file </button> </div> </div> - <button - className="mr-5 mb-10 text-xxs sm:text-sm border-2 w-32 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1" - onClick={handleRestore} - > + <button type="button" className="mr-5 mb-10 text-xxs sm:text-sm border-2 w-32 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1" onClick={handleRestore}> Restore </button> <div className="flex flex-col items-start justify-center"> diff --git a/src/pages/using-typescript.tsx b/src/pages/using-typescript.tsx deleted file mode 100644 index 55f52a55..00000000 --- a/src/pages/using-typescript.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// If you don't want to use TypeScript you can delete this file! -import React from 'react'; -import { PageProps, Link, graphql } from 'gatsby'; -import SEO from '../components/seo'; - -type DataProps = { - site: { - buildTime: string; - }; -}; - -const UsingTypescript: React.FC<PageProps<DataProps>> = ({ data, path }) => ( - <div> - <SEO title="Using TypeScript" /> - <h1>Gatsby supports TypeScript by default!</h1> - <p> - This means that you can create and write <em>.ts/.tsx</em> files for your pages, components etc. Please note that - the <em>gatsby-*.js</em> files (like gatsby-node.js) currently don't support TypeScript yet. - </p> - <p> - For type checking you'll want to install <em>typescript</em> via npm and run <em>tsc --init</em> to create a{' '} - <em>.tsconfig</em> file. - </p> - <p> - You're currently on the page "{path}" which was built on {data.site.buildTime}. - </p> - <p> - To learn more, head over to our{' '} - <a href="https://www.gatsbyjs.org/docs/typescript/">documentation about TypeScript</a>. - </p> - <Link to="/">Go back to the homepage</Link> - </div> -); - -export default UsingTypescript; - -export const query = graphql` - { - site { - buildTime(formatString: "YYYY-MM-DD hh:mm a z") - } - } -`; diff --git a/src/utils/link-generators.js b/src/utils/link-generators.js index 1f7e5f17..8d82ef27 100644 --- a/src/utils/link-generators.js +++ b/src/utils/link-generators.js @@ -9,29 +9,24 @@ const githubStatsStylingQueryString = (options) => { ...(options.cacheSeconds && { cache_seconds: options.cacheSeconds }), ...(options.locale && { locale: options.locale }), }; - const query_string = Object.entries(params) + const queryString = Object.entries(params) .map(([key, value]) => `${key}=${value}`) .join('&'); - return query_string; + return queryString; }; const streakStatsStylingQueryString = (options) => { const params = { ...(options.theme && options.theme !== 'none' && { theme: options.theme }), }; - const query_string = Object.entries(params) + const queryString = Object.entries(params) .map(([key, value]) => `${key}=${value}`) .join('&'); - return query_string; + return queryString; }; -export const githubStatsLinkGenerator = ({ github, options }) => - `https://github-readme-stats.vercel.app/api?username=${github}&${githubStatsStylingQueryString(options)}`; +export const githubStatsLinkGenerator = ({ github, options }) => `https://github-readme-stats.vercel.app/api?username=${github}&${githubStatsStylingQueryString(options)}`; -export const topLanguagesLinkGenerator = ({ github, options }) => - `https://github-readme-stats.vercel.app/api/top-langs?username=${github}&${githubStatsStylingQueryString( - options - )}&layout=compact`; +export const topLanguagesLinkGenerator = ({ github, options }) => `https://github-readme-stats.vercel.app/api/top-langs?username=${github}&${githubStatsStylingQueryString(options)}&layout=compact`; -export const streakStatsLinkGenerator = ({ github, options }) => - `https://github-readme-streak-stats.herokuapp.com/?user=${github}&${streakStatsStylingQueryString(options)}`; +export const streakStatsLinkGenerator = ({ github, options }) => `https://github-readme-streak-stats.herokuapp.com/?user=${github}&${streakStatsStylingQueryString(options)}`; diff --git a/src/utils/validation.js b/src/utils/validation.js index 11cdaceb..f6887fbe 100644 --- a/src/utils/validation.js +++ b/src/utils/validation.js @@ -1,5 +1,5 @@ const isGitHubUsernameValid = (username) => { - var pattern = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; + const pattern = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; return pattern.test(username); }; const isMediumUsernameValid = (username) => { @@ -10,7 +10,7 @@ const isMediumUsernameValid = (username) => { }; const isTwitterUsernameValid = (username) => { - var pattern = /^[a-zA-Z0-9_]{1,15}$/; + const pattern = /^[a-zA-Z0-9_]{1,15}$/; return pattern.test(username); }; diff --git a/src/utils/workflows.js b/src/utils/workflows.js index 20fb3334..123f9ba7 100644 --- a/src/utils/workflows.js +++ b/src/utils/workflows.js @@ -1,53 +1,27 @@ -import { isMediumUsernameValid } from '../utils/validation'; +import { isMediumUsernameValid } from './validation'; -const latestBlogs = (payload) => { +export default function latestBlogs(payload) { let rssFeed = ''; - if ( - payload.dev.show && - payload.dev.username && - payload.rssurl.show && - payload.rssurl.username && - payload.medium.show && - payload.medium.username && - isMediumUsernameValid(payload.medium.username) - ) { - rssFeed = - 'https://dev.to/feed/' + - payload.dev.username + - ', https://medium.com/feed/' + - payload.medium.username + - ', ' + - payload.rssurl.username; + if (payload.dev.show && payload.dev.username && payload.rssurl.show && payload.rssurl.username && payload.medium.show && payload.medium.username && isMediumUsernameValid(payload.medium.username)) { + rssFeed = `https://dev.to/feed/${payload.dev.username}, https://medium.com/feed/${payload.medium.username}, ${payload.rssurl.username}`; } - //when any two blog providers are selected + // when any two blog providers are selected else if (payload.dev.show && payload.dev.username && payload.rssurl.show && payload.rssurl.username) { - rssFeed = 'https://dev.to/feed/' + payload.dev.username + ', ' + payload.rssurl.username; - } else if ( - payload.rssurl.show && - payload.rssurl.username && - payload.medium.show && - payload.medium.username && - isMediumUsernameValid(payload.medium.username) - ) { - rssFeed = 'https://medium.com/feed/' + payload.medium.username + ', ' + payload.rssurl.username; - } else if ( - payload.dev.show && - payload.dev.username && - payload.medium.show && - payload.medium.username && - isMediumUsernameValid(payload.medium.username) - ) { - rssFeed = 'https://dev.to/feed/' + payload.dev.username + ', https://medium.com/feed/' + payload.medium.username; + rssFeed = `https://dev.to/feed/${payload.dev.username}, ${payload.rssurl.username}`; + } else if (payload.rssurl.show && payload.rssurl.username && payload.medium.show && payload.medium.username && isMediumUsernameValid(payload.medium.username)) { + rssFeed = `https://medium.com/feed/${payload.medium.username}, ${payload.rssurl.username}`; + } else if (payload.dev.show && payload.dev.username && payload.medium.show && payload.medium.username && isMediumUsernameValid(payload.medium.username)) { + rssFeed = `https://dev.to/feed/${payload.dev.username}, https://medium.com/feed/${payload.medium.username}`; } // when only one blog provider is selected else if (payload.dev.show && payload.dev.username) { - rssFeed = 'https://dev.to/feed/' + payload.dev.username; + rssFeed = `https://dev.to/feed/${payload.dev.username}`; } else if (payload.rssurl.show && payload.rssurl.username) { rssFeed = payload.rssurl.username; } else { - rssFeed = 'https://medium.com/feed/' + payload.medium.username; + rssFeed = `https://medium.com/feed/${payload.medium.username}`; } - let data = `name: Latest blog post workflow + const data = `name: Latest blog post workflow on: schedule: - cron: '0 * * * *' @@ -63,6 +37,4 @@ jobs: feed_list: "${rssFeed}"`; return data; -}; - -export { latestBlogs }; +}