fix: eslinting
This commit is contained in:
+4
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install lint-staged
|
||||
+4
-9
@@ -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"]
|
||||
}
|
||||
|
||||
Generated
+27
-4
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 (
|
||||
<>
|
||||
<div className="py-2 flex justify-start items-center text-sm sm:text-lg">
|
||||
<label htmlFor={inputId} className="checkbox-label flex items-center">
|
||||
<input
|
||||
id={inputId}
|
||||
type="checkbox"
|
||||
className="checkbox-label__input"
|
||||
checked={inputChecked}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
<span class="checkbox-label__control" />
|
||||
<span className="pl-4">{props.children}</span>
|
||||
</label>
|
||||
{Options && (
|
||||
<button
|
||||
id={`${inputId}-open-btn`}
|
||||
onClick={() => setOpen(!open)}
|
||||
className="flex ml-3 focus:bg-gray-400"
|
||||
style={{ outline: 'none' }}
|
||||
>
|
||||
<Icon className="transform scale-100 md:scale-125" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{Options && open && Options}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomizeOptions = ({ title, CustomizationOptions }) => (
|
||||
<div className={`border-2 border-solid border-gray-900 bg-gray-100 p-2 ml-8`} style={{ maxWidth: '21rem' }}>
|
||||
<header className="text-base sm:text-lg">{title}</header>
|
||||
<hr className="border-gray-500" />
|
||||
<div className="text-sm sm:text-lg flex flex-col mt-2 ml-0 md:ml-4">{CustomizationOptions}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const CustomizeBadge = ({ githubName, badgeOptions, onBadgeUpdate }) => {
|
||||
return (
|
||||
<>
|
||||
<label htmlFor="badge-style">
|
||||
Style:
|
||||
<select
|
||||
id="badge-style"
|
||||
onChange={(e) => onBadgeUpdate('badgeStyle', e.target.value)}
|
||||
value={badgeOptions.badgeStyle}
|
||||
>
|
||||
<option value="flat">Flat</option>
|
||||
<option value="flat-square">Flat Square</option>
|
||||
<option value="plastic">Plastic</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label htmlFor="badge-color">
|
||||
Color:
|
||||
<input
|
||||
type="color"
|
||||
id="badge-color"
|
||||
defaultValue={`#${badgeOptions.badgeColor}`}
|
||||
className="w-6"
|
||||
onChange={(e) => onBadgeUpdate('badgeColor', e.target.value.replace('#', ''))}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label htmlFor="badge-label-text">
|
||||
Label Text:
|
||||
<input
|
||||
type="text"
|
||||
id="badge-label-text"
|
||||
placeholder="Profile views"
|
||||
className="w-2/4 bg-gray-300 pl-2"
|
||||
onChange={(e) => onBadgeUpdate('badgeLabel', e.target.value.trim())}
|
||||
defaultValue={badgeOptions.badgeLabel}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<span className="mt-2 flex items-center">
|
||||
Preview:
|
||||
{isGitHubUsernameValid(githubName) ? (
|
||||
<img
|
||||
src={
|
||||
`https://komarev.com/ghpvc/` +
|
||||
`?username=${githubName}` +
|
||||
`&label=${encodeURI(badgeOptions.badgeLabel)}` +
|
||||
`&color=${badgeOptions.badgeColor}` +
|
||||
`&style=${badgeOptions.badgeStyle}`
|
||||
}
|
||||
alt="profile-visitors-count"
|
||||
/>
|
||||
) : (
|
||||
<span className="text-xxs md:text-sm text-red-600">Invalid GitHub username</span>
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomizeGithubStatsBase = ({ prefix, options, onUpdate }) => (
|
||||
<>
|
||||
<label htmlFor={`${prefix}-theme`}>
|
||||
Theme:
|
||||
<select
|
||||
id={`${prefix}-theme`}
|
||||
onChange={({ target: { value } }) => onUpdate('theme', value)}
|
||||
defaultValue={options.theme}
|
||||
>
|
||||
<option value="none">none</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="radical">Radical</option>
|
||||
<option value="merko">Merko</option>
|
||||
<option value="gruvbox">Gruvbox</option>
|
||||
<option value="tokyonight">Tokyonight</option>
|
||||
<option value="onedark">Onedark</option>
|
||||
<option value="cobalt">Cobalt</option>
|
||||
<option value="synthwave">Synthwave</option>
|
||||
<option value="highcontrast">Highcontrast</option>
|
||||
<option value="dracula">Dracula</option>
|
||||
</select>
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-title-color`}>
|
||||
Title Color:
|
||||
<input
|
||||
type="color"
|
||||
id={`${prefix}-title-color`}
|
||||
defaultValue={`#${options.titleColor}`}
|
||||
className="w-6"
|
||||
onChange={(e) => onUpdate('titleColor', e.target.value.replace('#', ''))}
|
||||
/>
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-text-color`}>
|
||||
Text Color:
|
||||
<input
|
||||
type="color"
|
||||
id={`${prefix}-text-color`}
|
||||
defaultValue={`#${options.textColor}`}
|
||||
className="w-6"
|
||||
onChange={(e) => onUpdate('textColor', e.target.value.replace('#', ''))}
|
||||
/>
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-bg-color`}>
|
||||
Background Color:
|
||||
<input
|
||||
type="color"
|
||||
id={`${prefix}-bg-color`}
|
||||
defaultValue={`#${options.bgColor}`}
|
||||
className="w-6"
|
||||
onChange={(e) => onUpdate('bgColor', e.target.value.replace('#', ''))}
|
||||
/>
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-hide-border`} className="checkbox-label">
|
||||
Hide border:
|
||||
<input
|
||||
id={`${prefix}-hide-border`}
|
||||
type="checkbox"
|
||||
className="checkbox-label__input"
|
||||
checked={options.hideBorder}
|
||||
onChange={(e) => onUpdate('hideBorder', e.target.checked)}
|
||||
/>
|
||||
<span class="checkbox-label__control" />
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-cache-seconds`}>
|
||||
Cache Seconds:
|
||||
<input
|
||||
id={`${prefix}-cache-seconds`}
|
||||
type="number"
|
||||
min={1800}
|
||||
max={86400}
|
||||
placeholder={1800}
|
||||
defaultValue={options.cacheSeconds}
|
||||
onChange={(e) => onUpdate('cacheSeconds', e.target.value)}
|
||||
/>
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-locale`}>
|
||||
Locale:
|
||||
<input
|
||||
id={`${prefix}-locale`}
|
||||
type="text"
|
||||
placeholder="en"
|
||||
defaultValue={options.locale}
|
||||
onChange={(e) => onUpdate('locale', e.target.value)}
|
||||
size="2"
|
||||
/>
|
||||
</label>
|
||||
</>
|
||||
);
|
||||
|
||||
const CustomizeStreakStats = ({ prefix, options, onUpdate }) => (
|
||||
<>
|
||||
<label htmlFor={`${prefix}-theme`}>
|
||||
Theme:
|
||||
<select
|
||||
id={`${prefix}-theme`}
|
||||
onChange={({ target: { value } }) => onUpdate('theme', value)}
|
||||
defaultValue={options.theme}
|
||||
>
|
||||
<option value="default">default</option>
|
||||
<option value="dark">dark</option>
|
||||
<option value="highcontrast">highcontrast</option>
|
||||
</select>
|
||||
</label>
|
||||
</>
|
||||
);
|
||||
|
||||
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 (
|
||||
<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">Add-ons</div>
|
||||
<AddonsItem
|
||||
inputId="visitors-count"
|
||||
inputChecked={props.data.visitorsBadge}
|
||||
onInputChange={() => props.handleCheckChange('visitorsBadge')}
|
||||
Options={
|
||||
<CustomizeOptions
|
||||
title="Customize Badge"
|
||||
CustomizationOptions={
|
||||
<CustomizeBadge
|
||||
githubName={props.social.github}
|
||||
badgeOptions={badgeOptions}
|
||||
onBadgeUpdate={onBadgeUpdate}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
display visitors count badge
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="github-profile-trophy"
|
||||
inputChecked={props.data.githubProfileTrophy}
|
||||
onInputChange={() => props.handleCheckChange('githubProfileTrophy')}
|
||||
>
|
||||
display github trophy
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="github-stats"
|
||||
inputChecked={props.data.githubStats}
|
||||
onInputChange={() => props.handleCheckChange('githubStats')}
|
||||
Options={
|
||||
<CustomizeOptions
|
||||
title="Customize Github Stats Card"
|
||||
CustomizationOptions={
|
||||
<CustomizeGithubStatsBase prefix="stats" options={githubStatsOptions} onUpdate={onStatsUpdate} />
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
display github profile stats card
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="top-languages"
|
||||
inputChecked={props.data.topLanguages}
|
||||
onInputChange={() => props.handleCheckChange('topLanguages')}
|
||||
Options={
|
||||
<CustomizeOptions
|
||||
title="Customize Top Skills Card"
|
||||
CustomizationOptions={
|
||||
<CustomizeGithubStatsBase prefix="top-lang" options={topLanguagesOptions} onUpdate={onTopLangUpdate} />
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
display top skills
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="streak-stats"
|
||||
inputChecked={props.data.streakStats}
|
||||
onInputChange={() => props.handleCheckChange('streakStats')}
|
||||
Options={
|
||||
<CustomizeOptions
|
||||
title="Customize Streak Stats Card"
|
||||
CustomizationOptions={
|
||||
<CustomizeStreakStats prefix="streak-stats" options={streakStatsOptions} onUpdate={onStreakStatsUpdate} />
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
display github streak stats
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="twitter-badge"
|
||||
inputChecked={props.data.twitterBadge}
|
||||
onInputChange={() => props.handleCheckChange('twitterBadge')}
|
||||
>
|
||||
display twitter badge
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="dev-dynamic-blogs"
|
||||
inputChecked={props.data.devDynamicBlogs}
|
||||
onInputChange={() => props.handleCheckChange('devDynamicBlogs')}
|
||||
>
|
||||
display latest dev.to blogs dynamically (GitHub Action)
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="medium-dynamic-blogs"
|
||||
inputChecked={props.data.mediumDynamicBlogs}
|
||||
onInputChange={() => props.handleCheckChange('mediumDynamicBlogs')}
|
||||
>
|
||||
display latest medium blogs dynamically (GitHub Action)
|
||||
</AddonsItem>
|
||||
<AddonsItem
|
||||
inputId="rss-dynamic-blogs"
|
||||
inputChecked={props.data.rssDynamicBlogs}
|
||||
onInputChange={() => props.handleCheckChange('rssDynamicBlogs')}
|
||||
>
|
||||
display latest blogs from your personal blog dynamically (GitHub Action)
|
||||
</AddonsItem>
|
||||
|
||||
{(props.data.devDynamicBlogs && props.social.dev) ||
|
||||
(props.data.rssDynamicBlogs && props.social.rssurl) ||
|
||||
(props.data.mediumDynamicBlogs && props.social.medium && isMediumUsernameValid(props.social.medium)) ? (
|
||||
<div className="workflow">
|
||||
<div>
|
||||
download
|
||||
<span
|
||||
id="blog-post-worklow-span"
|
||||
onClick={blogPostPorkflow}
|
||||
onKeyDown={(e) => e.keyCode === 13 && blogPostPorkflow()}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
style={{ cursor: 'pointer', color: '#002ead' }}
|
||||
>
|
||||
{' '}
|
||||
blog-post-workflow.yml
|
||||
</span>{' '}
|
||||
file(learn
|
||||
<a href={withPrefix(links.addons)} target="blank" style={{ color: '#002ead' }}>
|
||||
{' '}
|
||||
how to setup
|
||||
</a>
|
||||
)
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Addons;
|
||||
@@ -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 (
|
||||
<>
|
||||
<div className="py-2 flex justify-start items-center text-sm sm:text-lg">
|
||||
<label htmlFor={inputId} className="checkbox-label flex items-center">
|
||||
<input id={inputId} type="checkbox" className="checkbox-label__input" checked={inputChecked} onChange={onInputChange} />
|
||||
<span className="checkbox-label__control" />
|
||||
<span className="pl-4">{children}</span>
|
||||
</label>
|
||||
{Options && (
|
||||
<button type="button" id={`${inputId}-open-btn`} onClick={() => setOpen(!open)} className="flex ml-3 focus:bg-gray-400" style={{ outline: 'none' }}>
|
||||
<Icon className="transform scale-100 md:scale-125" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{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 }) => (
|
||||
<div className="border-2 border-solid border-gray-900 bg-gray-100 p-2 ml-8" style={{ maxWidth: '21rem' }}>
|
||||
<header className="text-base sm:text-lg">{title}</header>
|
||||
<hr className="border-gray-500" />
|
||||
<div className="text-sm sm:text-lg flex flex-col mt-2 ml-0 md:ml-4">{CustomizationOptions}</div>
|
||||
</div>
|
||||
);
|
||||
CustomizeOptions.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
CustomizationOptions: PropTypes.element.isRequired,
|
||||
};
|
||||
|
||||
const CustomizeBadge = ({ githubName, badgeOptions, onBadgeUpdate }) => (
|
||||
<>
|
||||
<label htmlFor="badge-style">
|
||||
Style:
|
||||
<select id="badge-style" onChange={(e) => onBadgeUpdate('badgeStyle', e.target.value)} value={badgeOptions.badgeStyle}>
|
||||
<option value="flat">Flat</option>
|
||||
<option value="flat-square">Flat Square</option>
|
||||
<option value="plastic">Plastic</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label htmlFor="badge-color">
|
||||
Color:
|
||||
<input type="color" id="badge-color" defaultValue={`#${badgeOptions.badgeColor}`} className="w-6" onChange={(e) => onBadgeUpdate('badgeColor', e.target.value.replace('#', ''))} />
|
||||
</label>
|
||||
|
||||
<label htmlFor="badge-label-text">
|
||||
Label Text:
|
||||
<input type="text" id="badge-label-text" placeholder="Profile views" className="w-2/4 bg-gray-300 pl-2" onChange={(e) => onBadgeUpdate('badgeLabel', e.target.value.trim())} defaultValue={badgeOptions.badgeLabel} />
|
||||
</label>
|
||||
|
||||
<span className="mt-2 flex items-center">
|
||||
Preview:
|
||||
{isGitHubUsernameValid(githubName) ? <img src={`https://komarev.com/ghpvc/?username=${githubName}&label=${encodeURI(badgeOptions.badgeLabel)}&color=${badgeOptions.badgeColor}&style=${badgeOptions.badgeStyle}`} alt="profile-visitors-count" /> : <span className="text-xxs md:text-sm text-red-600">Invalid GitHub username</span>}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
CustomizeBadge.propTypes = {
|
||||
githubName: PropTypes.string.isRequired,
|
||||
badgeOptions: PropTypes.object.isRequired,
|
||||
onBadgeUpdate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const CustomizeGithubStatsBase = ({ prefix, options, onUpdate }) => (
|
||||
<>
|
||||
<label htmlFor={`${prefix}-theme`}>
|
||||
Theme:
|
||||
<select id={`${prefix}-theme`} onChange={({ target: { value } }) => onUpdate('theme', value)} defaultValue={options.theme}>
|
||||
<option value="none">none</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="radical">Radical</option>
|
||||
<option value="merko">Merko</option>
|
||||
<option value="gruvbox">Gruvbox</option>
|
||||
<option value="tokyonight">Tokyonight</option>
|
||||
<option value="onedark">Onedark</option>
|
||||
<option value="cobalt">Cobalt</option>
|
||||
<option value="synthwave">Synthwave</option>
|
||||
<option value="highcontrast">Highcontrast</option>
|
||||
<option value="dracula">Dracula</option>
|
||||
</select>
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-title-color`}>
|
||||
Title Color:
|
||||
<input type="color" id={`${prefix}-title-color`} defaultValue={`#${options.titleColor}`} className="w-6" onChange={(e) => onUpdate('titleColor', e.target.value.replace('#', ''))} />
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-text-color`}>
|
||||
Text Color:
|
||||
<input type="color" id={`${prefix}-text-color`} defaultValue={`#${options.textColor}`} className="w-6" onChange={(e) => onUpdate('textColor', e.target.value.replace('#', ''))} />
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-bg-color`}>
|
||||
Background Color:
|
||||
<input type="color" id={`${prefix}-bg-color`} defaultValue={`#${options.bgColor}`} className="w-6" onChange={(e) => onUpdate('bgColor', e.target.value.replace('#', ''))} />
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-hide-border`} className="checkbox-label">
|
||||
Hide border:
|
||||
<input id={`${prefix}-hide-border`} type="checkbox" className="checkbox-label__input" checked={options.hideBorder} onChange={(e) => onUpdate('hideBorder', e.target.checked)} />
|
||||
<span className="checkbox-label__control" />
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-cache-seconds`}>
|
||||
Cache Seconds:
|
||||
<input id={`${prefix}-cache-seconds`} type="number" min={1800} max={86400} placeholder={1800} defaultValue={options.cacheSeconds} onChange={(e) => onUpdate('cacheSeconds', e.target.value)} />
|
||||
</label>
|
||||
<label htmlFor={`${prefix}-locale`}>
|
||||
Locale:
|
||||
<input id={`${prefix}-locale`} type="text" placeholder="en" defaultValue={options.locale} onChange={(e) => onUpdate('locale', e.target.value)} size="2" />
|
||||
</label>
|
||||
</>
|
||||
);
|
||||
CustomizeGithubStatsBase.propTypes = {
|
||||
prefix: PropTypes.string.isRequired,
|
||||
options: PropTypes.object.isRequired,
|
||||
onUpdate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const CustomizeStreakStats = ({ prefix, options, onUpdate }) => (
|
||||
<>
|
||||
<label htmlFor={`${prefix}-theme`}>
|
||||
Theme:
|
||||
<select id={`${prefix}-theme`} onChange={({ target: { value } }) => onUpdate('theme', value)} defaultValue={options.theme}>
|
||||
<option value="default">default</option>
|
||||
<option value="dark">dark</option>
|
||||
<option value="highcontrast">highcontrast</option>
|
||||
</select>
|
||||
</label>
|
||||
</>
|
||||
);
|
||||
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 (
|
||||
<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">Add-ons</div>
|
||||
<AddonsItem inputId="visitors-count" inputChecked={data.visitorsBadge} onInputChange={() => handleCheckChange('visitorsBadge')} Options={<CustomizeOptions title="Customize Badge" CustomizationOptions={<CustomizeBadge githubName={social.github} badgeOptions={badgeOptions} onBadgeUpdate={onBadgeUpdate} />} />}>
|
||||
display visitors count badge
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="github-profile-trophy" inputChecked={data.githubProfileTrophy} onInputChange={() => handleCheckChange('githubProfileTrophy')}>
|
||||
display github trophy
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="github-stats" inputChecked={data.githubStats} onInputChange={() => handleCheckChange('githubStats')} Options={<CustomizeOptions title="Customize Github Stats Card" CustomizationOptions={<CustomizeGithubStatsBase prefix="stats" options={githubStatsOptions} onUpdate={onStatsUpdate} />} />}>
|
||||
display github profile stats card
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="top-languages" inputChecked={data.topLanguages} onInputChange={() => handleCheckChange('topLanguages')} Options={<CustomizeOptions title="Customize Top Skills Card" CustomizationOptions={<CustomizeGithubStatsBase prefix="top-lang" options={topLanguagesOptions} onUpdate={onTopLangUpdate} />} />}>
|
||||
display top skills
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="streak-stats" inputChecked={data.streakStats} onInputChange={() => handleCheckChange('streakStats')} Options={<CustomizeOptions title="Customize Streak Stats Card" CustomizationOptions={<CustomizeStreakStats prefix="streak-stats" options={streakStatsOptions} onUpdate={onStreakStatsUpdate} />} />}>
|
||||
display github streak stats
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="twitter-badge" inputChecked={data.twitterBadge} onInputChange={() => handleCheckChange('twitterBadge')}>
|
||||
display twitter badge
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="dev-dynamic-blogs" inputChecked={data.devDynamicBlogs} onInputChange={() => handleCheckChange('devDynamicBlogs')}>
|
||||
display latest dev.to blogs dynamically (GitHub Action)
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="medium-dynamic-blogs" inputChecked={data.mediumDynamicBlogs} onInputChange={() => handleCheckChange('mediumDynamicBlogs')}>
|
||||
display latest medium blogs dynamically (GitHub Action)
|
||||
</AddonsItem>
|
||||
<AddonsItem inputId="rss-dynamic-blogs" inputChecked={data.rssDynamicBlogs} onInputChange={() => handleCheckChange('rssDynamicBlogs')}>
|
||||
display latest blogs from your personal blog dynamically (GitHub Action)
|
||||
</AddonsItem>
|
||||
|
||||
{(data.devDynamicBlogs && social.dev) || (data.rssDynamicBlogs && social.rssurl) || (data.mediumDynamicBlogs && social.medium && isMediumUsernameValid(social.medium)) ? (
|
||||
<div className="workflow">
|
||||
<div>
|
||||
download
|
||||
<span id="blog-post-worklow-span" onClick={blogPostPorkflow} onKeyDown={(e) => e.keyCode === 13 && blogPostPorkflow()} role="button" tabIndex="0" style={{ cursor: 'pointer', color: '#002ead' }}>
|
||||
{' '}
|
||||
blog-post-workflow.yml
|
||||
</span>{' '}
|
||||
file(learn
|
||||
<a href={withPrefix(links.addons)} target="blank" style={{ color: '#002ead' }}>
|
||||
{' '}
|
||||
how to setup
|
||||
</a>
|
||||
)
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Addons;
|
||||
Addons.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
social: PropTypes.object.isRequired,
|
||||
handleDataChange: PropTypes.func.isRequired,
|
||||
handleCheckChange: PropTypes.func.isRequired,
|
||||
};
|
||||
@@ -1,89 +0,0 @@
|
||||
import React from 'react';
|
||||
const Donate = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="text-center text-4xl my-2">
|
||||
Support
|
||||
<span role="img" aria-label="praying hand emoji">
|
||||
🙏
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row items-start justify-between">
|
||||
<div className="w-full sm:w-2/3">
|
||||
<div className="text-2xl mb-2">Are you using the tool and happy with it to create your GitHub Profile?</div>
|
||||
<div className="text-lg">Your kind support keeps open-source tools like this free for others.</div>
|
||||
<div className="mt-4">
|
||||
<a
|
||||
className="flex items-center justify-start w-20"
|
||||
href="https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator"
|
||||
>
|
||||
<img
|
||||
className="w-20"
|
||||
src="https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator"
|
||||
alt="tweet github profile readme generator"
|
||||
/>
|
||||
</a>
|
||||
Let the world know how you feel using this tool. Share with others on twitter.
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full sm:w-1/3 flex flex-col justify-center items-center">
|
||||
<span>
|
||||
Tip
|
||||
<span role="img" aria-label="Dollar medal">
|
||||
💰
|
||||
</span>
|
||||
</span>
|
||||
{/* Ko-Fi */}
|
||||
<a
|
||||
href="https://ko-fi.com/A0A81XXSX"
|
||||
className="flex items-center justify-evenly bg-red-500 text-white py-2 px-4 my-2"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<img
|
||||
className="w-6 h-6 mr-2"
|
||||
src="https://www.vectorlogo.zone/logos/ko-fi/ko-fi-icon.svg"
|
||||
alt="Buy ko-fi for rahuldkjain"
|
||||
/>
|
||||
Buy me a ko-fi
|
||||
</a>
|
||||
{/* Paypal */}
|
||||
<a
|
||||
href="https://www.paypal.me/rahuldkjain/10"
|
||||
className="flex items-center justify-evenly bg-white-500 text-white py-2 px-4 my-2 border border-solid"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<img
|
||||
className="w-32 h-4"
|
||||
src="https://cdn.worldvectorlogo.com/logos/paypal-2.svg"
|
||||
alt="Donate rahuldkjain via paypal"
|
||||
/>
|
||||
{/* <img
|
||||
className="w-6 h-6 mr-2"
|
||||
src="https://www.vectorlogo.zone/logos/paypal/paypal-ar21.svg"
|
||||
alt="Donate rahuldkjain via paypal"
|
||||
/>
|
||||
Paypal */}
|
||||
</a>
|
||||
{/* BuyMeACoffee */}
|
||||
<a
|
||||
href="https://www.buymeacoffee.com/rahuldkjain"
|
||||
className="flex items-center justify-evenly bg-orange-500 text-white py-2 px-4 my-2"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<img
|
||||
className="w-6 h-6 mr-2"
|
||||
src="https://www.vectorlogo.zone/logos/buymeacoffee/buymeacoffee-icon.svg"
|
||||
alt="Buy rahuldkjain A Coffee"
|
||||
/>
|
||||
Buy me a coffee
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Donate;
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
|
||||
const Donate = () => (
|
||||
<>
|
||||
<div className="text-center text-4xl my-2">
|
||||
Support
|
||||
<span role="img" aria-label="praying hand emoji">
|
||||
🙏
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row items-start justify-between">
|
||||
<div className="w-full sm:w-2/3">
|
||||
<div className="text-2xl mb-2">Are you using the tool and happy with it to create your GitHub Profile?</div>
|
||||
<div className="text-lg">Your kind support keeps open-source tools like this free for others.</div>
|
||||
<div className="mt-4">
|
||||
<a className="flex items-center justify-start w-20" href="https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator">
|
||||
<img className="w-20" src="https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator" alt="tweet github profile readme generator" />
|
||||
</a>
|
||||
Let the world know how you feel using this tool. Share with others on twitter.
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full sm:w-1/3 flex flex-col justify-center items-center">
|
||||
<span>
|
||||
Tip
|
||||
<span role="img" aria-label="Dollar medal">
|
||||
💰
|
||||
</span>
|
||||
</span>
|
||||
{/* Ko-Fi */}
|
||||
<a href="https://ko-fi.com/A0A81XXSX" className="flex items-center justify-evenly bg-red-500 text-white py-2 px-4 my-2" target="_blank" rel="noreferrer">
|
||||
<img className="w-6 h-6 mr-2" src="https://www.vectorlogo.zone/logos/ko-fi/ko-fi-icon.svg" alt="Buy ko-fi for rahuldkjain" />
|
||||
Buy me a ko-fi
|
||||
</a>
|
||||
{/* Paypal */}
|
||||
<a href="https://www.paypal.me/rahuldkjain/10" className="flex items-center justify-evenly bg-white-500 text-white py-2 px-4 my-2 border border-solid" target="_blank" rel="noreferrer">
|
||||
<img className="w-32 h-4" src="https://cdn.worldvectorlogo.com/logos/paypal-2.svg" alt="Donate rahuldkjain via paypal" />
|
||||
{/* <img
|
||||
className="w-6 h-6 mr-2"
|
||||
src="https://www.vectorlogo.zone/logos/paypal/paypal-ar21.svg"
|
||||
alt="Donate rahuldkjain via paypal"
|
||||
/>
|
||||
Paypal */}
|
||||
</a>
|
||||
{/* BuyMeACoffee */}
|
||||
<a href="https://www.buymeacoffee.com/rahuldkjain" className="flex items-center justify-evenly bg-orange-500 text-white py-2 px-4 my-2" target="_blank" rel="noreferrer">
|
||||
<img className="w-6 h-6 mr-2" src="https://www.vectorlogo.zone/logos/buymeacoffee/buymeacoffee-icon.svg" alt="Buy rahuldkjain A Coffee" />
|
||||
Buy me a coffee
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
export default Donate;
|
||||
@@ -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 (
|
||||
<div className="bg-gray-100 p-4 flex flex-col justify-center items-center shadow-inner mt-2">
|
||||
<div className="w-full flex flex-col sm:flex-row justify-evenly py-2">
|
||||
<div className="sm:ml-0 sm:mr-6 order-last sm:order-none flex">
|
||||
<h1 className="text-base font-bold font-title text-xl sm:text-2xl mt-3 sm:mt-0">
|
||||
<div className="flex sm:flex-col items-start mb-3 sm:mb-0">
|
||||
<img src={logo} className="hidden sm:block h-24" alt="github profile markdown generator logo" />
|
||||
<div className="mr-2 sm:mr-0">
|
||||
GitHub Profile{' '}
|
||||
<img src={logo} className="inline sm:hidden h-12" alt="github profile markdown generator logo" />
|
||||
<span className="block sm:inline">README Generator</span>
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="text-xl sm:text-base font-light sm:font-normal">
|
||||
<div className="font-title font-bold mb-4 sm:mb-2">
|
||||
<strong>Pages</strong>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<Link to={links.addons} activeStyle={{ color: '#002ead' }}>
|
||||
Addons
|
||||
</Link>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<Link to={links.support} activeStyle={{ color: '#002ead' }}>
|
||||
Support
|
||||
</Link>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<Link to={links.about} activeStyle={{ color: '#002ead' }}>
|
||||
About
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xl sm:text-base font-light sm:font-normal">
|
||||
<div className="font-title font-bold my-4 sm:my-0 sm:mb-2">
|
||||
<strong>More</strong>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a
|
||||
href="https://github.com/rahuldkjain/github-profile-readme-generator"
|
||||
aria-label="Github rahuldkjain/github-profile-readme-generator"
|
||||
target="blank"
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a
|
||||
href="https://github.com/rahuldkjain/github-profile-readme-generator/releases"
|
||||
aria-label="Releases on Github rahuldkjain/github-profile-readme-generator"
|
||||
target="blank"
|
||||
>
|
||||
Releases
|
||||
</a>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a
|
||||
href="https://github.com/rahuldkjain/github-profile-readme-generator/issues"
|
||||
aria-label="Issues in rahuldkjain/github-profile-readme-generator"
|
||||
target="blank"
|
||||
>
|
||||
Issues
|
||||
</a>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a
|
||||
href="https://github.com/rahuldkjain/github-profile-readme-generator/pulls"
|
||||
aria-label="Pull Requests in rahuldkjain/github-profile-readme-generator"
|
||||
target="blank"
|
||||
>
|
||||
Pull Requests
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-title font-bold text-xl sm:text-base my-4 sm:my-0 sm:mb-2">
|
||||
<strong>Join Community</strong>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a href="https://discord.gg/HHMs7Eg" aria-label="Discord of the community" target="blank">
|
||||
<img src={discord} className="h-12" alt="Discord of the community" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="py-2 mt-2">
|
||||
Developed in India{' '}
|
||||
<span role="img" aria-label="india">
|
||||
{' '}
|
||||
🇮🇳
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Footer;
|
||||
@@ -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 = () => (
|
||||
<div className="bg-gray-100 p-4 flex flex-col justify-center items-center shadow-inner mt-2">
|
||||
<div className="w-full flex flex-col sm:flex-row justify-evenly py-2">
|
||||
<div className="sm:ml-0 sm:mr-6 order-last sm:order-none flex">
|
||||
<h1 className="text-base font-bold font-title text-xl sm:text-2xl mt-3 sm:mt-0">
|
||||
<div className="flex sm:flex-col items-start mb-3 sm:mb-0">
|
||||
<img src={logo} className="hidden sm:block h-24" alt="github profile markdown generator logo" />
|
||||
<div className="mr-2 sm:mr-0">
|
||||
GitHub Profile <img src={logo} className="inline sm:hidden h-12" alt="github profile markdown generator logo" />
|
||||
<span className="block sm:inline">README Generator</span>
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="text-xl sm:text-base font-light sm:font-normal">
|
||||
<div className="font-title font-bold mb-4 sm:mb-2">
|
||||
<strong>Pages</strong>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<Link to={links.addons} activeStyle={{ color: '#002ead' }}>
|
||||
Addons
|
||||
</Link>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<Link to={links.support} activeStyle={{ color: '#002ead' }}>
|
||||
Support
|
||||
</Link>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<Link to={links.about} activeStyle={{ color: '#002ead' }}>
|
||||
About
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xl sm:text-base font-light sm:font-normal">
|
||||
<div className="font-title font-bold my-4 sm:my-0 sm:mb-2">
|
||||
<strong>More</strong>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a href="https://github.com/rahuldkjain/github-profile-readme-generator" aria-label="Github rahuldkjain/github-profile-readme-generator" target="blank">
|
||||
Github
|
||||
</a>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a href="https://github.com/rahuldkjain/github-profile-readme-generator/releases" aria-label="Releases on Github rahuldkjain/github-profile-readme-generator" target="blank">
|
||||
Releases
|
||||
</a>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a href="https://github.com/rahuldkjain/github-profile-readme-generator/issues" aria-label="Issues in rahuldkjain/github-profile-readme-generator" target="blank">
|
||||
Issues
|
||||
</a>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a href="https://github.com/rahuldkjain/github-profile-readme-generator/pulls" aria-label="Pull Requests in rahuldkjain/github-profile-readme-generator" target="blank">
|
||||
Pull Requests
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-title font-bold text-xl sm:text-base my-4 sm:my-0 sm:mb-2">
|
||||
<strong>Join Community</strong>
|
||||
</div>
|
||||
<div className="ml-2 sm:ml-0">
|
||||
<a href="https://discord.gg/HHMs7Eg" aria-label="Discord of the community" target="blank">
|
||||
<img src={discord} className="h-12" alt="Discord of the community" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="py-2 mt-2">
|
||||
Developed in India{' '}
|
||||
<span role="img" aria-label="india">
|
||||
{' '}
|
||||
🇮🇳
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
export default Footer;
|
||||
@@ -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) => {
|
||||
<Link to={links.home}>
|
||||
<h1 className="text-base font-bold font-title sm:text-2xl font-medium text-blue-800 flex justify-center items-center flex-col">
|
||||
<img src={logo} className="w-12 h-12" alt="github profile markdown generator logo" />
|
||||
<div>{props.heading}</div>
|
||||
<div>{heading}</div>
|
||||
</h1>
|
||||
</Link>
|
||||
<div className="flex justify-center items-center">
|
||||
<a
|
||||
href="https://github.com/rahuldkjain/github-profile-readme-generator"
|
||||
aria-label="Star rahuldkjain/github-profile-readme-generator on GitHub"
|
||||
target="blank"
|
||||
className="mr-2"
|
||||
>
|
||||
<a href="https://github.com/rahuldkjain/github-profile-readme-generator" aria-label="Star rahuldkjain/github-profile-readme-generator on GitHub" target="blank" className="mr-2">
|
||||
<div className="text-xxs sm:text-sm border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1 px-2">
|
||||
<StarIcon size={16} id="star-icon" className="px-1 w-6 star" />
|
||||
Star this repo
|
||||
<span className="github-count px-1 sm:px-2">{stats.starsCount}</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/rahuldkjain/github-profile-readme-generator/fork"
|
||||
aria-label="Fork rahuldkjain/github-profile-readme-generator on GitHub"
|
||||
target="blank"
|
||||
>
|
||||
<a href="https://github.com/rahuldkjain/github-profile-readme-generator/fork" aria-label="Fork rahuldkjain/github-profile-readme-generator on GitHub" target="blank">
|
||||
<div className="text-xxs sm:text-sm border-2 border-solid border-gray-900 bg-gray-100 flex items-center justify-center py-1 px-2">
|
||||
<RepoForkedIcon size={16} id="fork-icon" className="px-1 w-6 fork" />
|
||||
Fork on GitHub
|
||||
@@ -89,3 +81,6 @@ const Header = (props) => {
|
||||
};
|
||||
|
||||
export default Header;
|
||||
Header.propTypes = {
|
||||
heading: PropTypes.string.isRequired,
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import Header from './header';
|
||||
import Footer from './footer';
|
||||
|
||||
const Layout = ({ children }) => {
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen">
|
||||
<header>
|
||||
<Header heading="GitHub Profile README Generator" />
|
||||
</header>
|
||||
<main className="flex-grow">{children}</main>
|
||||
<footer>
|
||||
<Footer />
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Layout;
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Header from './header';
|
||||
import Footer from './footer';
|
||||
|
||||
const Layout = ({ children }) => (
|
||||
<div className="flex flex-col min-h-screen">
|
||||
<header>
|
||||
<Header heading="GitHub Profile README Generator" />
|
||||
</header>
|
||||
<main className="flex-grow">{children}</main>
|
||||
<footer>
|
||||
<Footer />
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
export default Layout;
|
||||
|
||||
Layout.defaultProps = {
|
||||
children: '',
|
||||
};
|
||||
|
||||
Layout.propTypes = {
|
||||
children: PropTypes.element,
|
||||
};
|
||||
@@ -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 (
|
||||
<div className="loader">
|
||||
<span ref={(el) => (arrow.current[0] = el)}>↓</span>
|
||||
<span ref={(el) => (arrow.current[1] = el)}>↓</span>
|
||||
<span ref={(el) => (arrow.current[2] = el)}>↓</span>
|
||||
<span ref={(el) => (arrow.current[3] = el)}>↓</span>
|
||||
<span ref={(el) => (arrow.current[4] = el)}>↓</span>
|
||||
<span
|
||||
ref={(el) => {
|
||||
arrow.current[0] = el;
|
||||
}}
|
||||
>
|
||||
↓
|
||||
</span>
|
||||
<span
|
||||
ref={(el) => {
|
||||
arrow.current[1] = el;
|
||||
}}
|
||||
>
|
||||
↓
|
||||
</span>
|
||||
<span
|
||||
ref={(el) => {
|
||||
arrow.current[2] = el;
|
||||
}}
|
||||
>
|
||||
↓
|
||||
</span>
|
||||
<span
|
||||
ref={(el) => {
|
||||
arrow.current[3] = el;
|
||||
}}
|
||||
>
|
||||
↓
|
||||
</span>
|
||||
<span
|
||||
ref={(el) => {
|
||||
arrow.current[4] = el;
|
||||
}}
|
||||
>
|
||||
↓
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<>
|
||||
{`<h1 align="center">${props.prefix + ' ' + props.title}</h1>`}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const SubTitle = (props) => {
|
||||
if (props.subtitle) {
|
||||
return (
|
||||
<>
|
||||
{`<h3 align="center">${props.subtitle}</h3>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const SectionTitle = (props) => {
|
||||
if (props.label) {
|
||||
return (
|
||||
<>
|
||||
{`<h3 align="left">${props.label}</h3>`}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const DisplayWork = (props) => {
|
||||
if (props.prefix && props.project) {
|
||||
if (props.link) {
|
||||
return (
|
||||
<>
|
||||
{`- ${props.prefix} [${props.project}](${props.link})`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
{`- ${props.prefix} **${props.project}**`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
if (props.prefix && props.link) {
|
||||
return (
|
||||
<>
|
||||
{`- ${props.prefix} [${props.link}](${props.link})`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const DisplaySocial = (props) => {
|
||||
if (props.username) {
|
||||
return (
|
||||
<>
|
||||
{`<a href="${props.base}/${props.username}" target="blank"><img align="center" src="${props.icon}" alt="${props.username}" height="30" width="40" /></a>`}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
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 (
|
||||
<>
|
||||
{`<p align="left"> <img src="${link}" alt="${props.github}" /> </p>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const TwitterBadge = (props) => {
|
||||
let link = 'https://img.shields.io/twitter/follow/' + props.twitter + '?logo=twitter&style=for-the-badge';
|
||||
if (props.show) {
|
||||
return (
|
||||
<>
|
||||
{`<p align="left"> <a href="${props.base}/${props.twitter}" target="blank"><img src="${link}" alt="${props.twitter}" /></a> </p>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const GithubProfileTrophy = (props) => {
|
||||
let link = 'https://github-profile-trophy.vercel.app/?username=' + props.github;
|
||||
if (props.show) {
|
||||
return (
|
||||
<>
|
||||
{`<p align="left"> <a href="https://github.com/ryo-ma/github-profile-trophy"><img src="${link}" alt="${props.github}" /></a> </p>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const GitHubStats = ({ show, github, options }) => {
|
||||
if (show) {
|
||||
return (
|
||||
<>
|
||||
{`<p> <img align="center" src="${githubStatsLinkGenerator({
|
||||
github: github,
|
||||
options,
|
||||
})}" alt="${github}" /></p>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
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(
|
||||
`
|
||||
<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 />
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
};
|
||||
const DisplayDynamicBlogs = (props) => {
|
||||
if (props.show) {
|
||||
return (
|
||||
<>
|
||||
{`### Blogs posts`}
|
||||
<br />
|
||||
{`<!-- BLOG-POST-LIST:START -->`}
|
||||
<br />
|
||||
{`<!-- BLOG-POST-LIST:END -->`}
|
||||
<br /> <br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const DisplayTopLanguages = (props) => {
|
||||
if (props.show) {
|
||||
if (!props.showStats) {
|
||||
return (
|
||||
<>
|
||||
{`<p><img align="center" src="${topLanguagesLinkGenerator({
|
||||
github: props.github,
|
||||
options: props.options,
|
||||
})}" alt="${props.github}" /></p>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{`<p><img align="left" src="${topLanguagesLinkGenerator({
|
||||
github: props.github,
|
||||
options: props.options,
|
||||
})}" alt="${props.github}" /></p>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const DisplayStreakStats = (props) => {
|
||||
if (props.show) {
|
||||
return (
|
||||
<>
|
||||
{`<p><img align="center" src="${streakStatsLinkGenerator({
|
||||
github: props.github,
|
||||
options: props.options,
|
||||
})}" alt="${props.github}" /></p>`}
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const DisplaySupport = (props) => {
|
||||
let viewSupport = false;
|
||||
Object.keys(props.support).forEach((key) => {
|
||||
if (props.support[key]) {
|
||||
viewSupport = true;
|
||||
}
|
||||
});
|
||||
return viewSupport ? (
|
||||
<div>
|
||||
<SectionTitle label="Support:" />
|
||||
{`<p>`}
|
||||
{props.support.buyMeACoffee &&
|
||||
`<a href="https://www.buymeacoffee.com/${props.support.buyMeACoffee}">
|
||||
<img align="left" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" height="50" width="210" alt="${props.support.buyMeACoffee}" /></a>`}
|
||||
{props.support.buyMeAKofi &&
|
||||
`<a href="https://ko-fi.com/${props.support.buyMeAKofi}">
|
||||
<img align="left" src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height="50" width="210" alt="${props.support.buyMeAKofi}" /></a>`}
|
||||
{`</p><br><br>`}
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
};
|
||||
const Markdown = (props) => {
|
||||
const icon_base_url =
|
||||
'https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/icons/Social/';
|
||||
|
||||
return (
|
||||
<div id="markdown-content" className="break-words">
|
||||
<>
|
||||
<Title prefix={props.prefix.title} title={props.data.title} />
|
||||
</>
|
||||
<>
|
||||
<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;
|
||||
@@ -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: {},
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -22,7 +22,7 @@ function SEO({ description, lang, meta, title }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`,
|
||||
);
|
||||
|
||||
const metaDescription = description || site.siteMetadata.description;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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">
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -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)}`;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
+14
-42
@@ -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 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user