Pass config as props
This commit is contained in:
parent
c6066fd038
commit
82eb282e17
@ -1,7 +1,8 @@
|
|||||||
|
import config from '../gitprofile.config';
|
||||||
import GitProfile from './components/GitProfile';
|
import GitProfile from './components/GitProfile';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return <GitProfile />;
|
return <GitProfile config={config} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@ -12,12 +12,12 @@ import Education from './education';
|
|||||||
import Project from './project';
|
import Project from './project';
|
||||||
import Blog from './blog';
|
import Blog from './blog';
|
||||||
import { getInitialTheme, setupHotjar } from '../helpers/utils';
|
import { getInitialTheme, setupHotjar } from '../helpers/utils';
|
||||||
import config from '../../gitprofile.config';
|
|
||||||
import '../assets/index.css';
|
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import '../assets/index.css';
|
||||||
|
|
||||||
const GitProfile = () => {
|
const GitProfile = ({ config }) => {
|
||||||
const [theme, setTheme] = useState(getInitialTheme());
|
const [theme, setTheme] = useState(getInitialTheme(config.themeConfig));
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [profile, setProfile] = useState(null);
|
const [profile, setProfile] = useState(null);
|
||||||
const [repo, setRepo] = useState(null);
|
const [repo, setRepo] = useState(null);
|
||||||
@ -31,7 +31,7 @@ const GitProfile = () => {
|
|||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setupHotjar();
|
setupHotjar(config.hotjar);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadData = useCallback(() => {
|
const loadData = useCallback(() => {
|
||||||
@ -113,7 +113,12 @@ const GitProfile = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<HeadTagEditor profile={profile} theme={theme} />
|
<HeadTagEditor
|
||||||
|
profile={profile}
|
||||||
|
theme={theme}
|
||||||
|
googleAnalytics={config.googleAnalytics}
|
||||||
|
social={config.social}
|
||||||
|
/>
|
||||||
<div className="fade-in h-screen">
|
<div className="fade-in h-screen">
|
||||||
{error ? (
|
{error ? (
|
||||||
<ErrorPage
|
<ErrorPage
|
||||||
@ -128,8 +133,7 @@ const GitProfile = () => {
|
|||||||
subTitle={
|
subTitle={
|
||||||
error === 404 ? (
|
error === 404 ? (
|
||||||
<p>
|
<p>
|
||||||
Please provide correct github username in{' '}
|
Please provide correct github username in <code>config</code>
|
||||||
<code>gitprofile.config.js</code>
|
|
||||||
</p>
|
</p>
|
||||||
) : error === 429 ? (
|
) : error === 429 ? (
|
||||||
<p>
|
<p>
|
||||||
@ -159,19 +163,37 @@ const GitProfile = () => {
|
|||||||
theme={theme}
|
theme={theme}
|
||||||
setTheme={setTheme}
|
setTheme={setTheme}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
themeConfig={config.themeConfig}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<AvatarCard profile={profile} loading={loading} />
|
<AvatarCard profile={profile} loading={loading} />
|
||||||
<Details profile={profile} loading={loading} />
|
<Details
|
||||||
<Skill loading={loading} />
|
profile={profile}
|
||||||
<Experience loading={loading} />
|
loading={loading}
|
||||||
<Education loading={loading} />
|
github={config.github}
|
||||||
|
social={config.social}
|
||||||
|
/>
|
||||||
|
<Skill loading={loading} skills={config.skills} />
|
||||||
|
<Experience
|
||||||
|
loading={loading}
|
||||||
|
experiences={config.experiences}
|
||||||
|
/>
|
||||||
|
<Education loading={loading} education={config.education} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="lg:col-span-2 col-span-1">
|
<div className="lg:col-span-2 col-span-1">
|
||||||
<div className="grid grid-cols-1 gap-6">
|
<div className="grid grid-cols-1 gap-6">
|
||||||
<Project repo={repo} loading={loading} />
|
<Project
|
||||||
<Blog loading={loading} />
|
repo={repo}
|
||||||
|
loading={loading}
|
||||||
|
github={config.github}
|
||||||
|
googleAnalytics={config.googleAnalytics}
|
||||||
|
/>
|
||||||
|
<Blog
|
||||||
|
loading={loading}
|
||||||
|
googleAnalytics={config.googleAnalytics}
|
||||||
|
blog={config.blog}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -204,4 +226,66 @@ const GitProfile = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GitProfile.propTypes = {
|
||||||
|
config: PropTypes.shape({
|
||||||
|
github: PropTypes.shape({
|
||||||
|
username: PropTypes.string.isRequired,
|
||||||
|
sortBy: PropTypes.oneOf(['stars', 'updated']).isRequired,
|
||||||
|
limit: PropTypes.number.isRequired,
|
||||||
|
exclude: PropTypes.shape({
|
||||||
|
forks: PropTypes.bool.isRequired,
|
||||||
|
projects: PropTypes.array.isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
social: PropTypes.shape({
|
||||||
|
linkedin: PropTypes.string,
|
||||||
|
twitter: PropTypes.string,
|
||||||
|
facebook: PropTypes.string,
|
||||||
|
dribbble: PropTypes.string,
|
||||||
|
behance: PropTypes.string,
|
||||||
|
medium: PropTypes.string,
|
||||||
|
devto: PropTypes.string,
|
||||||
|
website: PropTypes.string,
|
||||||
|
phone: PropTypes.string,
|
||||||
|
email: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
skills: PropTypes.array.isRequired,
|
||||||
|
experiences: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
company: PropTypes.string,
|
||||||
|
position: PropTypes.string,
|
||||||
|
from: PropTypes.string,
|
||||||
|
to: PropTypes.string,
|
||||||
|
})
|
||||||
|
).isRequired,
|
||||||
|
education: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
institution: PropTypes.string,
|
||||||
|
degree: PropTypes.string,
|
||||||
|
from: PropTypes.string,
|
||||||
|
to: PropTypes.string,
|
||||||
|
})
|
||||||
|
).isRequired,
|
||||||
|
blog: PropTypes.shape({
|
||||||
|
source: PropTypes.string,
|
||||||
|
username: PropTypes.string,
|
||||||
|
limit: PropTypes.number,
|
||||||
|
}).isRequired,
|
||||||
|
googleAnalytics: PropTypes.shape({
|
||||||
|
id: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
hotjar: PropTypes.shape({
|
||||||
|
id: PropTypes.string,
|
||||||
|
snippetVersion: PropTypes.number,
|
||||||
|
}).isRequired,
|
||||||
|
themeConfig: PropTypes.shape({
|
||||||
|
default: PropTypes.string.isRequired,
|
||||||
|
disableSwitch: PropTypes.bool.isRequired,
|
||||||
|
respectPrefersColorScheme: PropTypes.bool.isRequired,
|
||||||
|
themes: PropTypes.array.isRequired,
|
||||||
|
customTheme: PropTypes.object.isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
export default GitProfile;
|
export default GitProfile;
|
||||||
|
|||||||
@ -54,7 +54,7 @@ const AvatarCard = ({ profile, loading }) => {
|
|||||||
|
|
||||||
AvatarCard.propTypes = {
|
AvatarCard.propTypes = {
|
||||||
profile: PropTypes.object,
|
profile: PropTypes.object,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AvatarCard;
|
export default AvatarCard;
|
||||||
|
|||||||
@ -4,15 +4,14 @@ import { Fragment, useEffect, useState } from 'react';
|
|||||||
import { ga, skeleton } from '../../helpers/utils';
|
import { ga, skeleton } from '../../helpers/utils';
|
||||||
import LazyImage from '../lazy-image';
|
import LazyImage from '../lazy-image';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const displaySection = () => {
|
const displaySection = (blog) => {
|
||||||
if (
|
if (
|
||||||
typeof config.blog !== 'undefined' &&
|
typeof blog !== 'undefined' &&
|
||||||
typeof config.blog.source !== 'undefined' &&
|
typeof blog.source !== 'undefined' &&
|
||||||
typeof config.blog.username !== 'undefined' &&
|
typeof blog.username !== 'undefined' &&
|
||||||
config.blog.source &&
|
blog.source &&
|
||||||
config.blog.username
|
blog.username
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -20,20 +19,20 @@ const displaySection = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Blog = ({ loading }) => {
|
const Blog = ({ loading, blog, googleAnalytics }) => {
|
||||||
const [articles, setArticles] = useState(null);
|
const [articles, setArticles] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (displaySection()) {
|
if (displaySection(blog)) {
|
||||||
if (config.blog.source === 'medium') {
|
if (blog.source === 'medium') {
|
||||||
getMediumArticle({
|
getMediumArticle({
|
||||||
user: config.blog.username,
|
user: blog.username,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
setArticles(res);
|
setArticles(res);
|
||||||
});
|
});
|
||||||
} else if (config.blog.source === 'dev.to') {
|
} else if (blog.source === 'dev.to') {
|
||||||
getDevtoArticle({
|
getDevtoArticle({
|
||||||
user: config.blog.username,
|
user: blog.username,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
setArticles(res);
|
setArticles(res);
|
||||||
});
|
});
|
||||||
@ -43,7 +42,7 @@ const Blog = ({ loading }) => {
|
|||||||
|
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
for (let index = 0; index < config.blog.limit; index++) {
|
for (let index = 0; index < blog.limit; index++) {
|
||||||
array.push(
|
array.push(
|
||||||
<div className="card shadow-lg compact bg-base-100" key={index}>
|
<div className="card shadow-lg compact bg-base-100" key={index}>
|
||||||
<div className="p-8 h-full w-full">
|
<div className="p-8 h-full w-full">
|
||||||
@ -101,7 +100,7 @@ const Blog = ({ loading }) => {
|
|||||||
const renderArticles = () => {
|
const renderArticles = () => {
|
||||||
return (
|
return (
|
||||||
articles &&
|
articles &&
|
||||||
articles.slice(0, config.blog.limit).map((article, index) => (
|
articles.slice(0, blog.limit).map((article, index) => (
|
||||||
<a
|
<a
|
||||||
className="card shadow-lg compact bg-base-100 cursor-pointer"
|
className="card shadow-lg compact bg-base-100 cursor-pointer"
|
||||||
key={index}
|
key={index}
|
||||||
@ -110,7 +109,7 @@ const Blog = ({ loading }) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (config.googleAnalytics?.id) {
|
if (googleAnalytics?.id) {
|
||||||
ga.event({
|
ga.event({
|
||||||
action: 'Click Blog Post',
|
action: 'Click Blog Post',
|
||||||
params: {
|
params: {
|
||||||
@ -174,7 +173,7 @@ const Blog = ({ loading }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{displaySection() && (
|
{displaySection(blog) && (
|
||||||
<div className="col-span-1 lg:col-span-2">
|
<div className="col-span-1 lg:col-span-2">
|
||||||
<div className="grid grid-cols-2 gap-6">
|
<div className="grid grid-cols-2 gap-6">
|
||||||
<div className="col-span-2">
|
<div className="col-span-2">
|
||||||
@ -207,7 +206,9 @@ const Blog = ({ loading }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Blog.propTypes = {
|
Blog.propTypes = {
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
|
blog: PropTypes.object.isRequired,
|
||||||
|
googleAnalytics: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Blog;
|
export default Blog;
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import {
|
|||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { skeleton } from '../../helpers/utils';
|
import { skeleton } from '../../helpers/utils';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const ListItem = ({ icon, title, value, link, skeleton = false }) => {
|
const ListItem = ({ icon, title, value, link, skeleton = false }) => {
|
||||||
return (
|
return (
|
||||||
@ -43,7 +42,7 @@ const ListItem = ({ icon, title, value, link, skeleton = false }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Details = ({ profile, loading }) => {
|
const Details = ({ profile, loading, social, github }) => {
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
for (let index = 0; index < 4; index++) {
|
for (let index = 0; index < 4; index++) {
|
||||||
@ -86,99 +85,89 @@ const Details = ({ profile, loading }) => {
|
|||||||
<ListItem
|
<ListItem
|
||||||
icon={<AiFillGithub className="mr-2" />}
|
icon={<AiFillGithub className="mr-2" />}
|
||||||
title="GitHub:"
|
title="GitHub:"
|
||||||
value={config.github.username}
|
value={github.username}
|
||||||
link={`https://github.com/${config.github.username}`}
|
link={`https://github.com/${github.username}`}
|
||||||
/>
|
/>
|
||||||
{typeof config.social.twitter !== 'undefined' &&
|
{typeof social.twitter !== 'undefined' && social.twitter && (
|
||||||
config.social.twitter && (
|
<ListItem
|
||||||
<ListItem
|
icon={<SiTwitter className="mr-2" />}
|
||||||
icon={<SiTwitter className="mr-2" />}
|
title="Twitter:"
|
||||||
title="Twitter:"
|
value={social.twitter}
|
||||||
value={config.social.twitter}
|
link={`https://twitter.com/${social.twitter}`}
|
||||||
link={`https://twitter.com/${config.social.twitter}`}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
{typeof social.linkedin !== 'undefined' && social.linkedin && (
|
||||||
{typeof config.social.linkedin !== 'undefined' &&
|
<ListItem
|
||||||
config.social.linkedin && (
|
icon={<GrLinkedinOption className="mr-2" />}
|
||||||
<ListItem
|
title="LinkedIn:"
|
||||||
icon={<GrLinkedinOption className="mr-2" />}
|
value={social.linkedin}
|
||||||
title="LinkedIn:"
|
link={`https://www.linkedin.com/in/${social.linkedin}`}
|
||||||
value={config.social.linkedin}
|
/>
|
||||||
link={`https://www.linkedin.com/in/${config.social.linkedin}`}
|
)}
|
||||||
/>
|
{typeof social.dribbble !== 'undefined' && social.dribbble && (
|
||||||
)}
|
<ListItem
|
||||||
{typeof config.social.dribbble !== 'undefined' &&
|
icon={<CgDribbble className="mr-2" />}
|
||||||
config.social.dribbble && (
|
title="Dribbble:"
|
||||||
<ListItem
|
value={social.dribbble}
|
||||||
icon={<CgDribbble className="mr-2" />}
|
link={`https://dribbble.com/${social.dribbble}`}
|
||||||
title="Dribbble:"
|
/>
|
||||||
value={config.social.dribbble}
|
)}
|
||||||
link={`https://dribbble.com/${config.social.dribbble}`}
|
{typeof social.behance !== 'undefined' && social.behance && (
|
||||||
/>
|
<ListItem
|
||||||
)}
|
icon={<FaBehanceSquare className="mr-2" />}
|
||||||
{typeof config.social.behance !== 'undefined' &&
|
title="Behance:"
|
||||||
config.social.behance && (
|
value={social.behance}
|
||||||
<ListItem
|
link={`https://www.behance.net/${social.behance}`}
|
||||||
icon={<FaBehanceSquare className="mr-2" />}
|
/>
|
||||||
title="Behance:"
|
)}
|
||||||
value={config.social.behance}
|
{typeof social.facebook !== 'undefined' && social.facebook && (
|
||||||
link={`https://www.behance.net/${config.social.behance}`}
|
<ListItem
|
||||||
/>
|
icon={<FaFacebook className="mr-2" />}
|
||||||
)}
|
title="Facebook:"
|
||||||
{typeof config.social.facebook !== 'undefined' &&
|
value={social.facebook}
|
||||||
config.social.facebook && (
|
link={`https://www.facebook.com/${social.facebook}`}
|
||||||
<ListItem
|
/>
|
||||||
icon={<FaFacebook className="mr-2" />}
|
)}
|
||||||
title="Facebook:"
|
{typeof social.medium !== 'undefined' && social.medium && (
|
||||||
value={config.social.facebook}
|
<ListItem
|
||||||
link={`https://www.facebook.com/${config.social.facebook}`}
|
icon={<AiFillMediumSquare className="mr-2" />}
|
||||||
/>
|
title="Medium:"
|
||||||
)}
|
value={social.medium}
|
||||||
{typeof config.social.medium !== 'undefined' &&
|
link={`https://medium.com/@${social.medium}`}
|
||||||
config.social.medium && (
|
/>
|
||||||
<ListItem
|
)}
|
||||||
icon={<AiFillMediumSquare className="mr-2" />}
|
{typeof social.devto !== 'undefined' && social.devto && (
|
||||||
title="Medium:"
|
<ListItem
|
||||||
value={config.social.medium}
|
icon={<FaDev className="mr-2" />}
|
||||||
link={`https://medium.com/@${config.social.medium}`}
|
title="Dev:"
|
||||||
/>
|
value={social.devto}
|
||||||
)}
|
link={`https://dev.to/${social.devto}`}
|
||||||
{typeof config.social.devto !== 'undefined' &&
|
/>
|
||||||
config.social.devto && (
|
)}
|
||||||
<ListItem
|
{typeof social.website !== 'undefined' && social.website && (
|
||||||
icon={<FaDev className="mr-2" />}
|
<ListItem
|
||||||
title="Dev:"
|
icon={<FaGlobe className="mr-2" />}
|
||||||
value={config.social.devto}
|
title="Website:"
|
||||||
link={`https://dev.to/${config.social.devto}`}
|
value={social.website}
|
||||||
/>
|
link={social.website}
|
||||||
)}
|
/>
|
||||||
{typeof config.social.website !== 'undefined' &&
|
)}
|
||||||
config.social.website && (
|
{typeof social.phone !== 'undefined' && social.phone && (
|
||||||
<ListItem
|
<ListItem
|
||||||
icon={<FaGlobe className="mr-2" />}
|
icon={<RiPhoneFill className="mr-2" />}
|
||||||
title="Website:"
|
title="Phone:"
|
||||||
value={config.social.website}
|
value={social.phone}
|
||||||
link={config.social.website}
|
link={`tel:${social.phone}`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{typeof config.social.phone !== 'undefined' &&
|
{typeof social.email !== 'undefined' && social.email && (
|
||||||
config.social.phone && (
|
<ListItem
|
||||||
<ListItem
|
icon={<MdMail className="mr-2" />}
|
||||||
icon={<RiPhoneFill className="mr-2" />}
|
title="Email:"
|
||||||
title="Phone:"
|
value={social.email}
|
||||||
value={config.social.phone}
|
link={`mailto:${social.email}`}
|
||||||
link={`tel:${config.social.phone}`}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
|
||||||
{typeof config.social.email !== 'undefined' &&
|
|
||||||
config.social.email && (
|
|
||||||
<ListItem
|
|
||||||
icon={<MdMail className="mr-2" />}
|
|
||||||
title="Email:"
|
|
||||||
value={config.social.email}
|
|
||||||
link={`mailto:${config.social.email}`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -189,7 +178,9 @@ const Details = ({ profile, loading }) => {
|
|||||||
|
|
||||||
Details.propTypes = {
|
Details.propTypes = {
|
||||||
profile: PropTypes.object,
|
profile: PropTypes.object,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
|
social: PropTypes.object.isRequired,
|
||||||
|
github: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
ListItem.propTypes = {
|
ListItem.propTypes = {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { skeleton } from '../../helpers/utils';
|
import { skeleton } from '../../helpers/utils';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const ListItem = ({ time, degree, institution }) => (
|
const ListItem = ({ time, degree, institution }) => (
|
||||||
<li className="mb-5 ml-4">
|
<li className="mb-5 ml-4">
|
||||||
@ -15,7 +14,7 @@ const ListItem = ({ time, degree, institution }) => (
|
|||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
||||||
const Education = ({ loading }) => {
|
const Education = ({ loading, education }) => {
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
for (let index = 0; index < 2; index++) {
|
for (let index = 0; index < 2; index++) {
|
||||||
@ -41,46 +40,46 @@ const Education = ({ loading }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{typeof config.education !== 'undefined' &&
|
{typeof education !== 'undefined' && education.length !== 0 && (
|
||||||
config.education.length !== 0 && (
|
<div className="card shadow-lg compact bg-base-100">
|
||||||
<div className="card shadow-lg compact bg-base-100">
|
<div className="card-body">
|
||||||
<div className="card-body">
|
<div className="mx-3">
|
||||||
<div className="mx-3">
|
<h5 className="card-title">
|
||||||
<h5 className="card-title">
|
{loading ? (
|
||||||
{loading ? (
|
skeleton({ width: 'w-32', height: 'h-8' })
|
||||||
skeleton({ width: 'w-32', height: 'h-8' })
|
) : (
|
||||||
) : (
|
<span className="opacity-70">Education</span>
|
||||||
<span className="opacity-70">Education</span>
|
)}
|
||||||
)}
|
</h5>
|
||||||
</h5>
|
</div>
|
||||||
</div>
|
<div className="text-base-content text-opacity-60">
|
||||||
<div className="text-base-content text-opacity-60">
|
<ol className="relative border-l border-base-300 border-opacity-30 my-2 mx-4">
|
||||||
<ol className="relative border-l border-base-300 border-opacity-30 my-2 mx-4">
|
{loading ? (
|
||||||
{loading ? (
|
renderSkeleton()
|
||||||
renderSkeleton()
|
) : (
|
||||||
) : (
|
<Fragment>
|
||||||
<Fragment>
|
{education.map((item, index) => (
|
||||||
{config.education.map((item, index) => (
|
<ListItem
|
||||||
<ListItem
|
key={index}
|
||||||
key={index}
|
time={`${item.from} - ${item.to}`}
|
||||||
time={`${item.from} - ${item.to}`}
|
degree={item.degree}
|
||||||
degree={item.degree}
|
institution={item.institution}
|
||||||
institution={item.institution}
|
/>
|
||||||
/>
|
))}
|
||||||
))}
|
</Fragment>
|
||||||
</Fragment>
|
)}
|
||||||
)}
|
</ol>
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Education.propTypes = {
|
Education.propTypes = {
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
|
education: PropTypes.array.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
ListItem.propTypes = {
|
ListItem.propTypes = {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { skeleton } from '../../helpers/utils';
|
import { skeleton } from '../../helpers/utils';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const ListItem = ({ time, position, company }) => (
|
const ListItem = ({ time, position, company }) => (
|
||||||
<li className="mb-5 ml-4">
|
<li className="mb-5 ml-4">
|
||||||
@ -15,7 +14,7 @@ const ListItem = ({ time, position, company }) => (
|
|||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
||||||
const Experience = ({ loading }) => {
|
const Experience = ({ experiences, loading }) => {
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
for (let index = 0; index < 2; index++) {
|
for (let index = 0; index < 2; index++) {
|
||||||
@ -41,40 +40,39 @@ const Experience = ({ loading }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{typeof config.experiences !== 'undefined' &&
|
{typeof experiences !== 'undefined' && experiences.length !== 0 && (
|
||||||
config.experiences.length !== 0 && (
|
<div className="card shadow-lg compact bg-base-100">
|
||||||
<div className="card shadow-lg compact bg-base-100">
|
<div className="card-body">
|
||||||
<div className="card-body">
|
<div className="mx-3">
|
||||||
<div className="mx-3">
|
<h5 className="card-title">
|
||||||
<h5 className="card-title">
|
{loading ? (
|
||||||
{loading ? (
|
skeleton({ width: 'w-32', height: 'h-8' })
|
||||||
skeleton({ width: 'w-32', height: 'h-8' })
|
) : (
|
||||||
) : (
|
<span className="opacity-70">Experience</span>
|
||||||
<span className="opacity-70">Experience</span>
|
)}
|
||||||
)}
|
</h5>
|
||||||
</h5>
|
</div>
|
||||||
</div>
|
<div className="text-base-content text-opacity-60">
|
||||||
<div className="text-base-content text-opacity-60">
|
<ol className="relative border-l border-base-300 border-opacity-30 my-2 mx-4">
|
||||||
<ol className="relative border-l border-base-300 border-opacity-30 my-2 mx-4">
|
{loading ? (
|
||||||
{loading ? (
|
renderSkeleton()
|
||||||
renderSkeleton()
|
) : (
|
||||||
) : (
|
<Fragment>
|
||||||
<Fragment>
|
{experiences.map((experience, index) => (
|
||||||
{config.experiences.map((experience, index) => (
|
<ListItem
|
||||||
<ListItem
|
key={index}
|
||||||
key={index}
|
time={`${experience.from} - ${experience.to}`}
|
||||||
time={`${experience.from} - ${experience.to}`}
|
position={experience.position}
|
||||||
position={experience.position}
|
company={experience.company}
|
||||||
company={experience.company}
|
/>
|
||||||
/>
|
))}
|
||||||
))}
|
</Fragment>
|
||||||
</Fragment>
|
)}
|
||||||
)}
|
</ol>
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -86,7 +84,8 @@ ListItem.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Experience.propTypes = {
|
Experience.propTypes = {
|
||||||
loading: PropTypes.bool,
|
experiences: PropTypes.array.isRequired,
|
||||||
|
loading: PropTypes.bool.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Experience;
|
export default Experience;
|
||||||
|
|||||||
@ -2,25 +2,24 @@ import { Fragment } from 'react';
|
|||||||
import { Helmet } from 'react-helmet-async';
|
import { Helmet } from 'react-helmet-async';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { isThemeDarkish } from '../../helpers/utils';
|
import { isThemeDarkish } from '../../helpers/utils';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const HeadTagEditor = ({ profile, theme }) => {
|
const HeadTagEditor = ({ profile, theme, googleAnalytics, social }) => {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{profile && (
|
{profile && (
|
||||||
<Helmet>
|
<Helmet>
|
||||||
{config.googleAnalytics?.id && (
|
{googleAnalytics?.id && (
|
||||||
<script
|
<script
|
||||||
async
|
async
|
||||||
src={`https://www.googletagmanager.com/gtag/js?id=${config.googleAnalytics.id}`}
|
src={`https://www.googletagmanager.com/gtag/js?id=${googleAnalytics.id}`}
|
||||||
></script>
|
></script>
|
||||||
)}
|
)}
|
||||||
{config.googleAnalytics?.id && (
|
{googleAnalytics?.id && (
|
||||||
<script>
|
<script>
|
||||||
{`window.dataLayer = window.dataLayer || [];
|
{`window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag(){dataLayer.push(arguments);}
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
gtag('config', '${config.googleAnalytics.id}');`}
|
gtag('config', '${googleAnalytics.id}');`}
|
||||||
</script>
|
</script>
|
||||||
)}
|
)}
|
||||||
<title>Portfolio of {profile.name}</title>
|
<title>Portfolio of {profile.name}</title>
|
||||||
@ -38,9 +37,7 @@ const HeadTagEditor = ({ profile, theme }) => {
|
|||||||
<meta
|
<meta
|
||||||
property="og:url"
|
property="og:url"
|
||||||
content={
|
content={
|
||||||
typeof config.social.website !== 'undefined'
|
typeof social.website !== 'undefined' ? social.website : ''
|
||||||
? config.social.website
|
|
||||||
: ''
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
@ -60,7 +57,9 @@ const HeadTagEditor = ({ profile, theme }) => {
|
|||||||
|
|
||||||
HeadTagEditor.propTypes = {
|
HeadTagEditor.propTypes = {
|
||||||
profile: PropTypes.object,
|
profile: PropTypes.object,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string.isRequired,
|
||||||
|
googleAnalytics: PropTypes.object.isRequired,
|
||||||
|
social: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default HeadTagEditor;
|
export default HeadTagEditor;
|
||||||
|
|||||||
@ -2,12 +2,11 @@ import { Fragment } from 'react';
|
|||||||
import { AiOutlineStar, AiOutlineFork } from 'react-icons/ai';
|
import { AiOutlineStar, AiOutlineFork } from 'react-icons/ai';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { ga, languageColor, skeleton } from '../../helpers/utils';
|
import { ga, languageColor, skeleton } from '../../helpers/utils';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const Project = ({ repo, loading }) => {
|
const Project = ({ repo, loading, github, googleAnalytics }) => {
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
for (let index = 0; index < config.github.limit; index++) {
|
for (let index = 0; index < github.limit; index++) {
|
||||||
array.push(
|
array.push(
|
||||||
<div className="card shadow-lg compact bg-base-100" key={index}>
|
<div className="card shadow-lg compact bg-base-100" key={index}>
|
||||||
<div className="flex justify-between flex-col p-8 h-full w-full">
|
<div className="flex justify-between flex-col p-8 h-full w-full">
|
||||||
@ -61,7 +60,7 @@ const Project = ({ repo, loading }) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (config.googleAnalytics?.id) {
|
if (googleAnalytics?.id) {
|
||||||
ga.event({
|
ga.event({
|
||||||
action: 'Click project',
|
action: 'Click project',
|
||||||
params: {
|
params: {
|
||||||
@ -145,7 +144,7 @@ const Project = ({ repo, loading }) => {
|
|||||||
skeleton({ width: 'w-10', height: 'h-5' })
|
skeleton({ width: 'w-10', height: 'h-5' })
|
||||||
) : (
|
) : (
|
||||||
<a
|
<a
|
||||||
href={`https://github.com/${config.github.username}?tab=repositories`}
|
href={`https://github.com/${github.username}?tab=repositories`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="opacity-50"
|
className="opacity-50"
|
||||||
@ -170,7 +169,9 @@ const Project = ({ repo, loading }) => {
|
|||||||
|
|
||||||
Project.propTypes = {
|
Project.propTypes = {
|
||||||
repo: PropTypes.array,
|
repo: PropTypes.array,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
|
github: PropTypes.object.isRequired,
|
||||||
|
googleAnalytics: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Project;
|
export default Project;
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { skeleton } from '../../helpers/utils';
|
import { skeleton } from '../../helpers/utils';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const Skill = ({ loading }) => {
|
const Skill = ({ loading, skills }) => {
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
for (let index = 0; index < 12; index++) {
|
for (let index = 0; index < 12; index++) {
|
||||||
@ -18,7 +17,7 @@ const Skill = ({ loading }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{typeof config.skills !== 'undefined' && config.skills.length !== 0 && (
|
{typeof skills !== 'undefined' && skills.length !== 0 && (
|
||||||
<div className="card shadow-lg compact bg-base-100">
|
<div className="card shadow-lg compact bg-base-100">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className="mx-3">
|
<div className="mx-3">
|
||||||
@ -34,7 +33,7 @@ const Skill = ({ loading }) => {
|
|||||||
<div className="-m-1 flex flex-wrap justify-center">
|
<div className="-m-1 flex flex-wrap justify-center">
|
||||||
{loading
|
{loading
|
||||||
? renderSkeleton()
|
? renderSkeleton()
|
||||||
: config.skills.map((skill, index) => (
|
: skills.map((skill, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="m-1 text-xs inline-flex items-center font-bold leading-sm px-3 py-1 badge-primary bg-opacity-90 rounded-full"
|
className="m-1 text-xs inline-flex items-center font-bold leading-sm px-3 py-1 badge-primary bg-opacity-90 rounded-full"
|
||||||
@ -52,7 +51,8 @@ const Skill = ({ loading }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Skill.propTypes = {
|
Skill.propTypes = {
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
|
skills: PropTypes.array.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Skill;
|
export default Skill;
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { AiOutlineControl } from 'react-icons/ai';
|
import { AiOutlineControl } from 'react-icons/ai';
|
||||||
import { skeleton } from '../../helpers/utils';
|
import { skeleton } from '../../helpers/utils';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import config from '../../../gitprofile.config';
|
|
||||||
|
|
||||||
const ThemeChanger = ({ theme, setTheme, loading }) => {
|
const ThemeChanger = ({ theme, setTheme, loading, themeConfig }) => {
|
||||||
const changeTheme = (e, selectedTheme) => {
|
const changeTheme = (e, selectedTheme) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
document.querySelector('html').setAttribute('data-theme', selectedTheme);
|
document.querySelector('html').setAttribute('data-theme', selectedTheme);
|
||||||
@ -28,7 +27,7 @@ const ThemeChanger = ({ theme, setTheme, loading }) => {
|
|||||||
<span className="text-base-content text-opacity-40 capitalize text-sm">
|
<span className="text-base-content text-opacity-40 capitalize text-sm">
|
||||||
{loading
|
{loading
|
||||||
? skeleton({ width: 'w-16', height: 'h-5' })
|
? skeleton({ width: 'w-16', height: 'h-5' })
|
||||||
: theme === config.themeConfig.default
|
: theme === themeConfig.default
|
||||||
? 'Default'
|
? 'Default'
|
||||||
: theme}
|
: theme}
|
||||||
</span>
|
</span>
|
||||||
@ -62,9 +61,9 @@ const ThemeChanger = ({ theme, setTheme, loading }) => {
|
|||||||
>
|
>
|
||||||
<ul className="p-4 menu compact">
|
<ul className="p-4 menu compact">
|
||||||
{[
|
{[
|
||||||
config.themeConfig.default,
|
themeConfig.default,
|
||||||
...config.themeConfig.themes.filter(
|
...themeConfig.themes.filter(
|
||||||
(item) => item !== config.themeConfig.default
|
(item) => item !== themeConfig.default
|
||||||
),
|
),
|
||||||
].map((item, index) => (
|
].map((item, index) => (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
@ -74,9 +73,7 @@ const ThemeChanger = ({ theme, setTheme, loading }) => {
|
|||||||
className={`${theme === item ? 'active' : ''}`}
|
className={`${theme === item ? 'active' : ''}`}
|
||||||
>
|
>
|
||||||
<span className="opacity-60 capitalize">
|
<span className="opacity-60 capitalize">
|
||||||
{item === config.themeConfig.default
|
{item === themeConfig.default ? 'Default' : item}
|
||||||
? 'Default'
|
|
||||||
: item}
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -92,9 +89,10 @@ const ThemeChanger = ({ theme, setTheme, loading }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ThemeChanger.propTypes = {
|
ThemeChanger.propTypes = {
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string.isRequired,
|
||||||
setTheme: PropTypes.func,
|
setTheme: PropTypes.func.isRequired,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool.isRequired,
|
||||||
|
themeConfig: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ThemeChanger;
|
export default ThemeChanger;
|
||||||
|
|||||||
@ -1,32 +1,28 @@
|
|||||||
import colors from '../data/colors.json';
|
import colors from '../data/colors.json';
|
||||||
import { hotjar } from 'react-hotjar';
|
import { hotjar } from 'react-hotjar';
|
||||||
import config from '../../gitprofile.config';
|
|
||||||
|
|
||||||
export const getInitialTheme = () => {
|
export const getInitialTheme = (themeConfig) => {
|
||||||
if (config.themeConfig.disableSwitch) {
|
if (themeConfig.disableSwitch) {
|
||||||
return config.themeConfig.default;
|
return themeConfig.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof window !== 'undefined' &&
|
typeof window !== 'undefined' &&
|
||||||
!(localStorage.getItem('gitprofile-theme') === null) &&
|
!(localStorage.getItem('gitprofile-theme') === null) &&
|
||||||
config.themeConfig.themes.includes(localStorage.getItem('gitprofile-theme'))
|
themeConfig.themes.includes(localStorage.getItem('gitprofile-theme'))
|
||||||
) {
|
) {
|
||||||
let theme = localStorage.getItem('gitprofile-theme');
|
let theme = localStorage.getItem('gitprofile-theme');
|
||||||
|
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (themeConfig.respectPrefersColorScheme && !themeConfig.disableSwitch) {
|
||||||
config.themeConfig.respectPrefersColorScheme &&
|
|
||||||
!config.themeConfig.disableSwitch
|
|
||||||
) {
|
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
? 'dark'
|
? 'dark'
|
||||||
: config.themeConfig.default;
|
: themeConfig.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config.themeConfig.default;
|
return themeConfig.default;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const skeleton = ({
|
export const skeleton = ({
|
||||||
@ -92,12 +88,12 @@ export const isThemeDarkish = (theme) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setupHotjar = () => {
|
export const setupHotjar = (hotjarConfig) => {
|
||||||
if (config.hotjar?.id) {
|
if (hotjarConfig?.id) {
|
||||||
let snippetVersion = config.hotjar?.snippetVersion
|
let snippetVersion = hotjarConfig?.snippetVersion
|
||||||
? config.hotjar?.snippetVersion
|
? hotjarConfig?.snippetVersion
|
||||||
: 6;
|
: 6;
|
||||||
|
|
||||||
hotjar.initialize(config.hotjar.id, snippetVersion);
|
hotjar.initialize(hotjarConfig.id, snippetVersion);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user