Merge pull request #197 from arifszn/showcase

Showcase external projects
This commit is contained in:
Ariful Alam 2023-01-03 17:12:50 +06:00 committed by GitHub
commit 4eeb320f92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 261 additions and 6 deletions

View File

@ -266,6 +266,23 @@ const config = {
to: '2014',
},
],
// To hide the `Other Projects` section, keep it empty.
externalProjects: [
{
title: 'Project Name',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nunc ut.',
imageUrl: 'https://via.placeholder.com/250x250',
link: 'https://example.com',
},
{
title: 'Project Name',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nunc ut.',
imageUrl: 'https://via.placeholder.com/250x250',
link: 'https://example.com',
},
],
// Display blog posts from your medium or dev account. (Optional)
blog: {
source: 'dev', // medium | dev
@ -541,7 +558,9 @@ Empty array will hide the certifications section.
### Projects
Your public repo from GitHub will be displayed here automatically. You can limit how many projects do you want to be displayed. Also, you can hide forked or specific repo.
#### Github Projects
Your public repo from GitHub will be displayed in the `Github Projects` section automatically. You can limit how many projects do you want to be displayed. Also, you can hide forked or specific repo.
```js
// gitprofile.config.js
@ -559,6 +578,25 @@ module.exports = {
};
```
#### External Projects
In this section you can showcase your external/personal projects.
```js
// gitprofile.config.js
module.exports = {
// ...
externalProjects: [
{
title: 'Project Name',
description: 'Description',
link: 'https://example.com',
imageUrl: 'https://via.placeholder.com/250x250',
},
],
};
```
### Blog Posts
If you have [medium](https://medium.com) or [dev](https://dev.to) account, you can show your recent blog posts in here just by providing your medium/dev username. You can limit how many posts to display (Max is `10`).

View File

@ -82,6 +82,25 @@ const config = {
to: '2014',
},
],
// To hide the `Other Projects` section, keep it empty.
externalProjects: [
{
title: 'Project Name',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nunc ut.',
imageUrl: 'https://via.placeholder.com/250x250',
link: 'https://example.com',
},
{
title: 'Project Name',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nunc ut.',
imageUrl: 'https://via.placeholder.com/250x250',
link: 'https://example.com',
},
],
// Display blog posts from your medium or dev account. (Optional)
blog: {
source: 'dev', // medium | dev

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "@arifszn/gitprofile",
"version": "2.1.0",
"version": "2.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@arifszn/gitprofile",
"version": "2.1.0",
"version": "2.2.0",
"license": "MIT",
"dependencies": {
"react": "^18.2.0",

View File

@ -1,7 +1,7 @@
{
"name": "@arifszn/gitprofile",
"description": "Create an automatic portfolio based on GitHub profile",
"version": "2.1.0",
"version": "2.2.0",
"license": "MIT",
"author": "arifszn",
"repository": {

View File

@ -25,6 +25,7 @@ import { HelmetProvider } from 'react-helmet-async';
import PropTypes from 'prop-types';
import '../assets/index.css';
import { formatDistance } from 'date-fns';
import ExternalProject from './external-project';
const bgColor = 'bg-base-300';
@ -202,6 +203,11 @@ const GitProfile = ({ config }) => {
github={sanitizedConfig.github}
googleAnalytics={sanitizedConfig.googleAnalytics}
/>
<ExternalProject
loading={loading}
externalProjects={sanitizedConfig.externalProjects}
googleAnalytics={sanitizedConfig.googleAnalytics}
/>
<Blog
loading={loading}
googleAnalytics={sanitizedConfig.googleAnalytics}
@ -269,6 +275,14 @@ GitProfile.propTypes = {
email: PropTypes.string,
}),
skills: PropTypes.array,
externalProjects: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
link: PropTypes.string.isRequired,
imageUrl: PropTypes.string,
})
),
experiences: PropTypes.arrayOf(
PropTypes.shape({
company: PropTypes.string,

View File

@ -0,0 +1,171 @@
import { Fragment } from 'react';
import PropTypes from 'prop-types';
import { ga, skeleton } from '../../helpers/utils';
import LazyImage from '../lazy-image';
const displaySection = (externalProjects) => {
if (
externalProjects &&
Array.isArray(externalProjects) &&
externalProjects.length
) {
return true;
} else {
return false;
}
};
const ExternalProject = ({ externalProjects, loading, googleAnalytics }) => {
const renderSkeleton = () => {
let array = [];
for (let index = 0; index < externalProjects.length; index++) {
array.push(
<div className="card shadow-lg compact bg-base-100" key={index}>
<div className="p-8 h-full w-full">
<div className="flex items-center flex-col">
<div className="w-full">
<div className="flex items-start px-4">
<div className="w-full">
<h2>
{skeleton({
width: 'w-32',
height: 'h-8',
className: 'mb-2 mx-auto',
})}
</h2>
<div className="avatar w-full h-full">
<div className="w-20 h-20 mask mask-squircle mx-auto">
{skeleton({
width: 'w-full',
height: 'h-full',
shape: '',
})}
</div>
</div>
<div className="mt-2">
{skeleton({
width: 'w-full',
height: 'h-4',
className: 'mx-auto',
})}
</div>
<div className="mt-2 flex items-center flex-wrap justify-center">
{skeleton({
width: 'w-full',
height: 'h-4',
className: 'mx-auto',
})}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
return array;
};
const renderExternalProjects = () => {
return externalProjects.map((item, index) => (
<a
className="card shadow-lg compact bg-base-100 cursor-pointer"
key={index}
href={item.link}
onClick={(e) => {
e.preventDefault();
try {
if (googleAnalytics?.id) {
ga.event({
action: 'Click External Project',
params: {
post: item.title,
},
});
}
} catch (error) {
console.error(error);
}
window?.open(item.link, '_blank');
}}
>
<div className="p-8 h-full w-full">
<div className="flex items-center flex-col">
<div className="w-full">
<div className="px-4">
<div className="text-center w-full">
<h2 className="font-semibold text-base-content opacity-60 mb-2">
{item.title}
</h2>
{item.imageUrl && (
<div className="avatar opacity-90">
<div className="w-20 h-20 mask mask-squircle">
<LazyImage
src={item.imageUrl}
alt={'thumbnail'}
placeholder={skeleton({
width: 'w-full',
height: 'h-full',
shape: '',
})}
/>
</div>
</div>
)}
<p className="mt-1 text-base-content text-opacity-60 text-sm">
{item.description}
</p>
</div>
</div>
</div>
</div>
</div>
</a>
));
};
return (
<Fragment>
{displaySection(externalProjects) && (
<div className="col-span-1 lg:col-span-2">
<div className="grid grid-cols-2 gap-6">
<div className="col-span-2">
<div className="card compact bg-gradient-to-br to-base-200 from-base-100 shadow">
<div className="card-body">
<div className="mx-3 flex items-center justify-between mb-2">
<h5 className="card-title">
{loading ? (
skeleton({ width: 'w-40', height: 'h-8' })
) : (
<span className="text-base-content opacity-70">
My Projects
</span>
)}
</h5>
</div>
<div className="col-span-2">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading ? renderSkeleton() : renderExternalProjects()}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</Fragment>
);
};
ExternalProject.propTypes = {
externalProjects: PropTypes.array,
loading: PropTypes.bool.isRequired,
googleAnalytics: PropTypes.object,
};
export default ExternalProject;

View File

@ -141,10 +141,10 @@ const Project = ({ repo, loading, github, googleAnalytics }) => {
<div className="mx-3 flex items-center justify-between mb-2">
<h5 className="card-title">
{loading ? (
skeleton({ width: 'w-28', height: 'h-8' })
skeleton({ width: 'w-40', height: 'h-8' })
) : (
<span className="text-base-content opacity-70">
My Projects
GitHub Projects
</span>
)}
</h5>

View File

@ -162,6 +162,7 @@ export const sanitizeConfig = (config) => {
fileUrl: config?.resume?.fileUrl || '',
},
skills: config?.skills || [],
externalProjects: config?.externalProjects || [],
experiences: config?.experiences || [],
certifications: config?.certifications || [],
education: config?.education || [],

12
types/index.d.ts vendored
View File

@ -221,6 +221,13 @@ export interface Certifications {
link?: string;
}
export interface ExternalProjects {
title: string;
description: string;
imageUrl?: string;
link: string;
}
export interface Education {
institution?: string;
degree?: string;
@ -258,6 +265,11 @@ export interface Config {
*/
experiences?: Array<Experience>;
/**
* External Projects
*/
externalProjects?: Array<ExternalProjects>;
/**
* Certifications list
*/