mirror of
https://github.com/NohamR/gitprofile.git
synced 2026-05-25 20:00:25 +00:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9280f317ee | ||
|
|
893f52ee96 | ||
|
|
529b4047f3 | ||
|
|
5d2fafa0b0 | ||
|
|
2d4376645d | ||
|
|
545212d7f5 | ||
|
|
a0557a1691 | ||
|
|
d19f490d26 | ||
|
|
f4cfcbbe5e | ||
|
|
a1f983ef16 | ||
|
|
d8880234e0 | ||
|
|
654a5449bb | ||
|
|
daa1212e66 | ||
|
|
30399395c1 | ||
|
|
fd6d5a09dd | ||
|
|
23f07cc8ef | ||
|
|
2ded9a0625 | ||
|
|
f5c197e2c5 | ||
|
|
49db2972c2 | ||
|
|
5da67dfcc0 | ||
|
|
2fd66cc027 | ||
|
|
fadc5f3f7e | ||
|
|
edd365ef01 | ||
|
|
16aadfa664 | ||
|
|
1cadcc1f59 | ||
|
|
03c566615a | ||
|
|
7a4d8aefdf | ||
|
|
d9de322944 | ||
|
|
bc5bec50f4 | ||
|
|
e6006e387a | ||
|
|
e4005d288d | ||
|
|
0424045f55 | ||
|
|
a71c4ca330 | ||
|
|
ebf5af2451 | ||
|
|
6477cceb86 | ||
|
|
8f167cc940 | ||
|
|
d5c715e16e | ||
|
|
343ad767f0 | ||
|
|
fd1a96c160 | ||
|
|
de964e620b | ||
|
|
bb7c671e3b | ||
|
|
67246fd888 | ||
|
|
9b7a270f92 | ||
|
|
31181711df | ||
|
|
c4241c65b9 | ||
|
|
a69bee5cd0 | ||
|
|
d7696f070e | ||
|
|
6041dc51aa | ||
|
|
b3c06be528 | ||
|
|
d36d0f74e1 | ||
|
|
5b337e1ddb | ||
|
|
1a054c39b6 | ||
|
|
287e750548 | ||
|
|
07cd0ad4ed | ||
|
|
2d1cf94612 | ||
|
|
71d2c30130 |
39
.github/workflows/CI-CD.yml
vendored
Normal file
39
.github/workflows/CI-CD.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: Build and Publish to gh-pages Branch
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '14'
|
||||||
|
|
||||||
|
- name: Cache dependencies
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
**/node_modules
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build
|
||||||
|
env:
|
||||||
|
CI: ""
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
uses: JamesIves/github-pages-deploy-action@4.1.4
|
||||||
|
with:
|
||||||
|
branch: gh-pages
|
||||||
|
folder: build
|
||||||
2
LICENSE
2
LICENSE
@@ -186,7 +186,7 @@
|
|||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
Copyright 2022 Ariful Alam
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
98
README.md
98
README.md
@@ -18,12 +18,13 @@
|
|||||||
<a href="#arifszn"><img src="https://arifszn.github.io/assets/img/drop-shadow.png" width="60%" alt="Shadow"/></a>
|
<a href="#arifszn"><img src="https://arifszn.github.io/assets/img/drop-shadow.png" width="60%" alt="Shadow"/></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
**ezProfile** is an easy-to-customize personal dev portfolio builder that is created with React.js. When you manage the code in a GitHub repository, it will automatically render a webpage with the owner's profile information, including a photo, bio, and repositories. Also, it includes space to highlight your details, job history, education history, skills, and recent blog posts.
|
**ezProfile** is an easy-to-customize personal dev portfolio builder that is created with React.js. When you manage the code in a GitHub repository, it will automatically render a webpage with the owner's profile information, including a photo, bio, and public repositories. Also, it includes space to highlight your details, job history, education history, skills, and recent blog posts.
|
||||||
|
|
||||||
It's all possible using [GitHub API](https://developer.github.com/v3/) (for automatically populating your website with content) and [Article-api](https://github.com/arifszn/article-api) (for fetching recent blog posts).
|
It's all possible using [GitHub API](https://developer.github.com/v3/) (for automatically populating your website with content) and [Article-api](https://github.com/arifszn/article-api) (for fetching recent blog posts).
|
||||||
|
|
||||||
✓ [21 Themes](#themes)\
|
✓ [21 Themes](#themes)\
|
||||||
✓ [Google Analytics](#google-analytics)\
|
✓ [Google Analytics](#google-analytics)\
|
||||||
|
✓ [Hotjar](#hotjar)\
|
||||||
✓ [Meta Tags](#meta-tags)\
|
✓ [Meta Tags](#meta-tags)\
|
||||||
✓ [Avatar and Bio](#avatar-and-bio)\
|
✓ [Avatar and Bio](#avatar-and-bio)\
|
||||||
✓ [Social Links](#social-links)\
|
✓ [Social Links](#social-links)\
|
||||||
@@ -36,31 +37,41 @@ It's all possible using [GitHub API](https://developer.github.com/v3/) (for auto
|
|||||||
To view a live example, **[click here](https://arifszn.github.io/ezprofile)**.
|
To view a live example, **[click here](https://arifszn.github.io/ezprofile)**.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 🛠 Installation & Set Up
|
## 🛠 Installation & Set Up
|
||||||
|
|
||||||
These instructions will get you a copy of the project up and running on your local machine.
|
These instructions will get you a copy of the project and deploy your website online!
|
||||||
|
|
||||||
You'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer.
|
- **[Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo)** the repo so you have your own project to customize by clicking the fork icon on the top right side. A "fork" is a copy of a repository.
|
||||||
|
- Rename your forked repository to <code>username.github.io</code> in github, where <code>username</code> is your GitHub username (or organization name).
|
||||||
|
- Go to your repo's **Actions** page and enable workflows.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
1. **[Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo)** the repo so you have your own project to customize. A "fork" is a copy of a repository.
|
- Open <code>package.json</code>, and change <code>homepage</code>'s value to <code>https://username.github.io</code>.
|
||||||
|
|
||||||
2. Once you've found a home for your forked repository, **[clone](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository-from-github/cloning-a-repository)** it.
|
```js
|
||||||
|
// package.json
|
||||||
3. Change into your new directory.
|
{
|
||||||
```sh
|
// ...
|
||||||
cd ezprofile
|
"homepage": "https://username.github.io",
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Install dependencies
|
- Now commit to your **main** branch with your changes.
|
||||||
```sh
|
- The CI/CD pipeline will publish your page at the gh-pages branch automatically.
|
||||||
npm install
|
- Go to your repo's **Settings** -> **Pages** -> **Source** and change the branch to gh-pages and click **save**.
|
||||||
```
|
- Your personal portfolio will be live at <code>username.github.io</code>.
|
||||||
|
- Any time you commit a change to the **main** branch, the website will be automatically updated.
|
||||||
|
|
||||||
|
|
||||||
|
You can skip the above steps and do a manual deployment by running <code>npm run deploy</code>. For more info, visit [here](https://create-react-app.dev/docs/deployment/#github-pages).
|
||||||
|
|
||||||
|
As this is a create react app, you can also host your website to Netlify, Vercel, Heroku, or other popular services. Please refer to this [doc](https://create-react-app.dev/docs/deployment) for a detailed deployment guide to other services.
|
||||||
|
|
||||||
|
If you see only <code>README</code> at <code>username.github.io</code>, be sure to change your GitHub Page's source to <code>gh-pages</code> branch. See [how to](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site). Also, if you face any issue rendering the website, double-check the `homepage` value in the package.json.
|
||||||
|
|
||||||
|
|
||||||
5. Start the development server
|
|
||||||
```sh
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎨 Customization
|
## 🎨 Customization
|
||||||
|
|
||||||
@@ -92,6 +103,7 @@ module.exports = {
|
|||||||
medium: '',
|
medium: '',
|
||||||
devto: '',
|
devto: '',
|
||||||
website: '',
|
website: '',
|
||||||
|
phone: '',
|
||||||
email: ''
|
email: ''
|
||||||
},
|
},
|
||||||
skills: [
|
skills: [
|
||||||
@@ -136,6 +148,10 @@ module.exports = {
|
|||||||
// GA3 tracking id/GA4 tag id
|
// GA3 tracking id/GA4 tag id
|
||||||
id: '' // UA-XXXXXXXXX-X | G-XXXXXXXXXX
|
id: '' // UA-XXXXXXXXX-X | G-XXXXXXXXXX
|
||||||
},
|
},
|
||||||
|
hotjar: {
|
||||||
|
id: '',
|
||||||
|
snippetVersion : 6
|
||||||
|
},
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
default: 'light',
|
default: 'light',
|
||||||
|
|
||||||
@@ -226,8 +242,22 @@ module.exports = {
|
|||||||
|
|
||||||
Besides tracking visitors, ezFolio will track click events on projects and blog posts, and send them to Google Analytics.\
|
Besides tracking visitors, ezFolio will track click events on projects and blog posts, and send them to Google Analytics.\
|
||||||
<br/>
|
<br/>
|
||||||

|

|
||||||
|
|
||||||
|
### Hotjar
|
||||||
|
|
||||||
|
ezProfile supports hotjar. If you do not want to use Hotjar, keep the <code>id</code> empty.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// config.js
|
||||||
|
module.exports = {
|
||||||
|
// ...
|
||||||
|
hotjar: {
|
||||||
|
id: '',
|
||||||
|
snippetVersion : 6
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Meta Tags
|
### Meta Tags
|
||||||
|
|
||||||
@@ -243,7 +273,7 @@ Your github avatar and bio will be displayed here.\
|
|||||||
|
|
||||||
### Social Links
|
### Social Links
|
||||||
|
|
||||||
ezProfile supports linking your social media services you're using, including LinkedIn, Twitter, Facebook, Dribbble, Behance, Medium, dev.to, personal website, and email.
|
ezProfile supports linking your social media services you're using, including LinkedIn, Twitter, Facebook, Dribbble, Behance, Medium, dev.to, personal website, phone and email.
|
||||||
```js
|
```js
|
||||||
// config.js
|
// config.js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -257,6 +287,7 @@ module.exports = {
|
|||||||
medium: '',
|
medium: '',
|
||||||
devto: '',
|
devto: '',
|
||||||
website: 'https://arifszn.github.io',
|
website: 'https://arifszn.github.io',
|
||||||
|
phone: '',
|
||||||
email: ''
|
email: ''
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -375,35 +406,10 @@ module.exports = {
|
|||||||
The posts are fetched by [Article-api](https://github.com/arifszn/article-api).
|
The posts are fetched by [Article-api](https://github.com/arifszn/article-api).
|
||||||
|
|
||||||
|
|
||||||
## 🚀 Deploy
|
|
||||||
|
|
||||||
Once you are done with your setup and have completed all steps above, you need to put your website online! The fastest approach is to use [GitHub Pages](https://pages.github.com) which is completely free.
|
|
||||||
|
|
||||||
**1. Github Pages:**
|
|
||||||
- Rename your forked repository to <code>username.github.io</code> in github, where <code>username</code> is your GitHub username (or organization name).
|
|
||||||
- Open <code>package.json</code>, and change <code>homepage</code>'s value to <code>https://username.github.io</code>.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// package.json
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
"homepage": "https://username.github.io",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- Run <code>npm run deploy</code>.
|
|
||||||
- If you see only <code>README</code> at <code>username.github.io</code>, be sure to change your GitHub Page's source to <code>gh-pages</code> branch. See [how to](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site).
|
|
||||||
|
|
||||||
Your personal portfolio will be live at <code>username.github.io</code>. For more info, visit [here](https://create-react-app.dev/docs/deployment/#github-pages).
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
**2. Other:** You can also host your website to Netlify, Vercel, Heroku, or other popular services. Please refer to this [doc](https://create-react-app.dev/docs/deployment) for a detailed deployment guide.
|
|
||||||
|
|
||||||
|
|
||||||
## 📢 Please Read
|
## 📢 Please Read
|
||||||
|
|
||||||
I intend to keep my works open source. Please do not discourage me by claiming this work by copying it as your own or removing the footer notice.
|
I intend to keep my works open source. Please do not discourage me by claiming this work by copying it as your own. However, You are open to use this project by forking it and change any code necessary by giving attribute to the original author. Please see this [issue](https://github.com/arifszn/ezprofile/issues/11) for more info.
|
||||||
|
|
||||||
|
|
||||||
## 💖 Support
|
## 💖 Support
|
||||||
@@ -417,4 +423,4 @@ Any contributors who want to make this project better can make contributions, wh
|
|||||||
|
|
||||||
## 📄 License
|
## 📄 License
|
||||||
|
|
||||||
ezProfile is licensed under the [Apache-2.0 License](https://github.com/arifszn/ezprofile/blob/main/LICENSE).
|
**ezProfile** is licensed under the [Apache-2.0 License](https://github.com/arifszn/ezprofile/blob/main/LICENSE).
|
||||||
|
|||||||
8110
package-lock.json
generated
8110
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ezprofile",
|
"name": "ezprofile",
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"description": "Kickstart your personal portfolio with Github Api and blog",
|
"description": "Kickstart your personal portfolio with Github Api and blog",
|
||||||
"homepage": "https://arifszn.github.io/ezprofile",
|
"homepage": "https://arifszn.github.io/ezprofile",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -12,12 +12,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@craco/craco": "^6.2.0",
|
"@craco/craco": "^6.2.0",
|
||||||
"@reduxjs/toolkit": "^1.6.1",
|
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
"article-api": "^1.0.5",
|
"article-api": "^1.0.5",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.23.0",
|
||||||
"daisyui": "^1.12.1",
|
"daisyui": "^1.12.1",
|
||||||
"gh-pages": "^3.2.3",
|
"gh-pages": "^3.2.3",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
@@ -25,8 +24,8 @@
|
|||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-helmet-async": "^1.1.0",
|
"react-helmet-async": "^1.1.0",
|
||||||
|
"react-hotjar": "^3.0.1",
|
||||||
"react-icons": "^4.2.0",
|
"react-icons": "^4.2.0",
|
||||||
"react-redux": "^7.2.4",
|
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"sass": "^1.38.0",
|
"sass": "^1.38.0",
|
||||||
"web-vitals": "^1.0.1"
|
"web-vitals": "^1.0.1"
|
||||||
|
|||||||
39
src/App.js
39
src/App.js
@@ -1,26 +1,25 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { Fragment, useCallback, useEffect, useState } from "react";
|
import { Fragment, useCallback, useContext, useEffect, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
|
||||||
import AvatarCard from "./components/AvatarCard";
|
import AvatarCard from "./components/AvatarCard";
|
||||||
import ErrorPage from "./components/ErrorPage";
|
import ErrorPage from "./components/ErrorPage";
|
||||||
import ThemeChanger from "./components/ThemeChanger";
|
import ThemeChanger from "./components/ThemeChanger";
|
||||||
import config from "./config";
|
import config from "./config";
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { setLoading } from "./store/slices/loadingSlice";
|
|
||||||
import { setProfile } from "./store/slices/profileSlice";
|
|
||||||
import Details from "./components/Details";
|
import Details from "./components/Details";
|
||||||
import Skill from "./components/Skill";
|
import Skill from "./components/Skill";
|
||||||
import Experience from "./components/Experience";
|
import Experience from "./components/Experience";
|
||||||
import Education from "./components/Education";
|
import Education from "./components/Education";
|
||||||
import Project from "./components/Project";
|
import Project from "./components/Project";
|
||||||
import { setRepo } from "./store/slices/repoSlice";
|
|
||||||
import Blog from "./components/Blog";
|
import Blog from "./components/Blog";
|
||||||
import MetaTags from "./components/MetaTags";
|
import MetaTags from "./components/MetaTags";
|
||||||
|
import { LoadingContext } from "./contexts/LoadingContext";
|
||||||
|
import { ThemeContext } from "./contexts/ThemeContext";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const dispatch = useDispatch();
|
const [theme] = useContext(ThemeContext);
|
||||||
const theme = useSelector(state => state.theme);
|
const [, setLoading] = useContext(LoadingContext);
|
||||||
|
const [profile, setProfile] = useState(null);
|
||||||
|
const [repo, setRepo] = useState(null);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const [rateLimit, setRateLimit] = useState(null);
|
const [rateLimit, setRateLimit] = useState(null);
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ function App() {
|
|||||||
company: data.company ? data.company : ''
|
company: data.company ? data.company : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(setProfile(profileData));
|
setProfile(profileData);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
let excludeRepo = ``;
|
let excludeRepo = ``;
|
||||||
@@ -64,7 +63,7 @@ function App() {
|
|||||||
.then(response => {
|
.then(response => {
|
||||||
let data = response.data;
|
let data = response.data;
|
||||||
|
|
||||||
dispatch(setRepo(data.items));
|
setRepo(data.items);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
@@ -74,9 +73,9 @@ function App() {
|
|||||||
handleError(error);
|
handleError(error);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
dispatch(setLoading(false));
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}, [dispatch])
|
}, [setLoading])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadData();
|
loadData();
|
||||||
@@ -91,7 +90,7 @@ function App() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (error.response.status === 403) {
|
if (error.response.status === 403) {
|
||||||
setError(403);
|
setError(429);
|
||||||
} else if (error.response.status === 404) {
|
} else if (error.response.status === 404) {
|
||||||
setError(404);
|
setError(404);
|
||||||
} else {
|
} else {
|
||||||
@@ -104,7 +103,7 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<MetaTags/>
|
<MetaTags profile={profile}/>
|
||||||
<div className="fade-in h-screen">
|
<div className="fade-in h-screen">
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -112,7 +111,7 @@ function App() {
|
|||||||
<ErrorPage
|
<ErrorPage
|
||||||
status={`${error}`}
|
status={`${error}`}
|
||||||
title={(error === 404) ? 'The Github Username is Incorrect' : (
|
title={(error === 404) ? 'The Github Username is Incorrect' : (
|
||||||
error === 403 ? 'Too Many Request.' : `Ops!!`
|
error === 429 ? 'Too Many Requests.' : `Ops!!`
|
||||||
)}
|
)}
|
||||||
subTitle={
|
subTitle={
|
||||||
(error === 404) ? (
|
(error === 404) ? (
|
||||||
@@ -120,7 +119,7 @@ function App() {
|
|||||||
Please provide correct github username in <code>src\config.js</code>
|
Please provide correct github username in <code>src\config.js</code>
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
error === 403 ? (
|
error === 429 ? (
|
||||||
<p>
|
<p>
|
||||||
Oh no, you hit the{' '}
|
Oh no, you hit the{' '}
|
||||||
<a
|
<a
|
||||||
@@ -147,8 +146,8 @@ function App() {
|
|||||||
<ThemeChanger/>
|
<ThemeChanger/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<AvatarCard />
|
<AvatarCard profile={profile}/>
|
||||||
<Details />
|
<Details profile={profile}/>
|
||||||
<Skill/>
|
<Skill/>
|
||||||
<Experience/>
|
<Experience/>
|
||||||
<Education/>
|
<Education/>
|
||||||
@@ -156,13 +155,13 @@ function App() {
|
|||||||
</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 />
|
<Project repo={repo}/>
|
||||||
<Blog/>
|
<Blog/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* DO NOT REMOVE/MODIFY THE FOOTER */}
|
{/* DO NOT REMOVE/MODIFY THE FOOTER. FOR MORE INFO https://github.com/arifszn/ezprofile#-please-read */}
|
||||||
<footer className="p-4 footer bg-base-200 text-base-content footer-center">
|
<footer className="p-4 footer bg-base-200 text-base-content footer-center">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-mono text-sm">Made with <a className="text-primary" href="https://github.com/arifszn/ezprofile" target="_blank" rel="noreferrer">ezProfile</a> and ❤️</p>
|
<p className="font-mono text-sm">Made with <a className="text-primary" href="https://github.com/arifszn/ezprofile" target="_blank" rel="noreferrer">ezProfile</a> and ❤️</p>
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { useSelector } from "react-redux";
|
|
||||||
import { fallbackImage, skeleton } from "../helpers/utils";
|
import { fallbackImage, skeleton } from "../helpers/utils";
|
||||||
import LazyImage from "./LazyImage";
|
import LazyImage from "./LazyImage";
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { LoadingContext } from "../contexts/LoadingContext";
|
||||||
|
|
||||||
const AvatarCard = () => {
|
const AvatarCard = (props) => {
|
||||||
const profile = useSelector(state => state.profile);
|
const [loading] = useContext(LoadingContext);
|
||||||
const loading = useSelector(state => state.loading);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card shadow-lg compact bg-base-100">
|
<div className="card shadow-lg compact bg-base-100">
|
||||||
<div className="grid place-items-center py-8">
|
<div className="grid place-items-center py-8">
|
||||||
{
|
{
|
||||||
loading ? (
|
(loading || !props.profile) ? (
|
||||||
<div className="avatar opacity-90">
|
<div className="avatar opacity-90">
|
||||||
<div className="mb-8 rounded-full w-32 h-32">
|
<div className="mb-8 rounded-full w-32 h-32">
|
||||||
{
|
{
|
||||||
@@ -27,8 +28,8 @@ const AvatarCard = () => {
|
|||||||
<div className="mb-8 rounded-full w-32 h-32 ring ring-primary ring-offset-base-100 ring-offset-2">
|
<div className="mb-8 rounded-full w-32 h-32 ring ring-primary ring-offset-base-100 ring-offset-2">
|
||||||
{
|
{
|
||||||
<LazyImage
|
<LazyImage
|
||||||
src={profile.avatar ? profile.avatar : fallbackImage}
|
src={props.profile.avatar ? props.profile.avatar : fallbackImage}
|
||||||
alt={profile.name}
|
alt={props.profile.name}
|
||||||
placeholder={
|
placeholder={
|
||||||
skeleton({
|
skeleton({
|
||||||
width: 'w-full',
|
width: 'w-full',
|
||||||
@@ -42,19 +43,19 @@ const AvatarCard = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div className="text-center mx-auto md:mx-8">
|
<div className="text-center mx-auto px-8">
|
||||||
<h5 className="font-bold text-2xl">
|
<h5 className="font-bold text-2xl">
|
||||||
{
|
{
|
||||||
loading ? (
|
(loading || !props.profile) ? (
|
||||||
skeleton({ width: 'w-48', height: 'h-8' })
|
skeleton({ width: 'w-48', height: 'h-8' })
|
||||||
) : <span className="opacity-70">{profile.name}</span>
|
) : <span className="opacity-70">{props.profile.name}</span>
|
||||||
}
|
}
|
||||||
</h5>
|
</h5>
|
||||||
<div className="mt-3 text-base-content text-opacity-60">
|
<div className="mt-3 text-base-content text-opacity-60">
|
||||||
{
|
{
|
||||||
loading ? (
|
(loading || !props.profile) ? (
|
||||||
skeleton({ width: 'w-48', height: 'h-5' })
|
skeleton({ width: 'w-48', height: 'h-5' })
|
||||||
) : profile.bio
|
) : props.profile.bio
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,4 +64,8 @@ const AvatarCard = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvatarCard.propTypes = {
|
||||||
|
profile: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
export default AvatarCard;
|
export default AvatarCard;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { getDevtoArticle, getMediumArticle } from "article-api";
|
import { getDevtoArticle, getMediumArticle } from "article-api";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { Fragment, useEffect, useState } from "react";
|
import { Fragment, useContext, useEffect, useState } from "react";
|
||||||
import { CgHashtag } from 'react-icons/cg';
|
import { CgHashtag } from 'react-icons/cg';
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
import { LoadingContext } from "../contexts/LoadingContext";
|
||||||
import { ga, skeleton } from "../helpers/utils";
|
import { ga, skeleton } from "../helpers/utils";
|
||||||
import LazyImage from "./LazyImage";
|
import LazyImage from "./LazyImage";
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ const displaySection = () => {
|
|||||||
|
|
||||||
const Blog = () => {
|
const Blog = () => {
|
||||||
const [articles, setArticles] = useState(null);
|
const [articles, setArticles] = useState(null);
|
||||||
const loading = useSelector(state => state.loading);
|
const [loading] = useContext(LoadingContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (displaySection()) {
|
if (displaySection()) {
|
||||||
@@ -95,7 +95,7 @@ const Blog = () => {
|
|||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
try {
|
try {
|
||||||
if (config.googleAnalytics.id) {
|
if (config.googleAnalytics?.id) {
|
||||||
ga.event({
|
ga.event({
|
||||||
action: "Click Blog Post",
|
action: "Click Blog Post",
|
||||||
params: {
|
params: {
|
||||||
@@ -141,7 +141,7 @@ const Blog = () => {
|
|||||||
{
|
{
|
||||||
article.categories.map((category, index2) => (
|
article.categories.map((category, index2) => (
|
||||||
<div key={index2} className="flex text-sm mr-3 items-center opacity-50 font-bold font-mono">
|
<div key={index2} className="flex text-sm mr-3 items-center opacity-50 font-bold font-mono">
|
||||||
<CgHashtag />
|
<span><CgHashtag /></span>
|
||||||
<span>{category}</span>
|
<span>{category}</span>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -3,14 +3,16 @@ import { AiFillGithub, AiFillMediumSquare } from 'react-icons/ai';
|
|||||||
import { SiTwitter } from 'react-icons/si';
|
import { SiTwitter } from 'react-icons/si';
|
||||||
import { GrLinkedinOption } from 'react-icons/gr';
|
import { GrLinkedinOption } from 'react-icons/gr';
|
||||||
import { CgDribbble } from 'react-icons/cg';
|
import { CgDribbble } from 'react-icons/cg';
|
||||||
|
import { RiPhoneFill } from 'react-icons/ri';
|
||||||
import { FaBehanceSquare, FaBuilding, FaDev, FaFacebook, FaGlobe } from 'react-icons/fa';
|
import { FaBehanceSquare, FaBuilding, FaDev, FaFacebook, FaGlobe } from 'react-icons/fa';
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { skeleton } from '../helpers/utils';
|
import { skeleton } from '../helpers/utils';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { LoadingContext } from '../contexts/LoadingContext';
|
||||||
|
|
||||||
const Details = () => {
|
const Details = (props) => {
|
||||||
const profile = useSelector(state => state.profile);
|
const [loading] = useContext(LoadingContext);
|
||||||
const loading = useSelector(state => state.loading);
|
|
||||||
|
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
@@ -33,31 +35,42 @@ const Details = () => {
|
|||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<ul className="menu row-span-3 bg-base-100 text-base-content text-opacity-60">
|
<ul className="menu row-span-3 bg-base-100 text-base-content text-opacity-60">
|
||||||
{
|
{
|
||||||
loading ? renderSkeleton() : (
|
(loading || !props.profile) ? renderSkeleton() : (
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
profile && profile.location && (
|
props.profile.location && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<MdLocationOn className="mr-2"/>
|
<MdLocationOn className="mr-2"/>
|
||||||
{profile.location}
|
</div>
|
||||||
|
<div>
|
||||||
|
{props.profile.location}
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
profile && profile.company && (
|
props.profile.company && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<FaBuilding className="mr-2"/>
|
<FaBuilding className="mr-2"/>
|
||||||
{profile.company}
|
</div>
|
||||||
|
<div>
|
||||||
|
{props.profile.company}
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<AiFillGithub className="mr-2"/>
|
<AiFillGithub className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://github.com/${config.github.username}`}
|
href={`https://github.com/${config.github.username}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -66,13 +79,17 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.github.username}
|
{config.github.username}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{
|
{
|
||||||
typeof config.social.linkedin !== 'undefined' && config.social.linkedin && (
|
typeof config.social.linkedin !== 'undefined' && config.social.linkedin && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<GrLinkedinOption className="mr-2"/>
|
<GrLinkedinOption className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://www.linkedin.com/in/${config.social.linkedin}`}
|
href={`https://www.linkedin.com/in/${config.social.linkedin}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -81,6 +98,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.linkedin}
|
{config.social.linkedin}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -89,7 +107,10 @@ const Details = () => {
|
|||||||
typeof config.social.twitter !== 'undefined' && config.social.twitter && (
|
typeof config.social.twitter !== 'undefined' && config.social.twitter && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<SiTwitter className="mr-2"/>
|
<SiTwitter className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://twitter.com/${config.social.twitter}`}
|
href={`https://twitter.com/${config.social.twitter}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -98,6 +119,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.twitter}
|
{config.social.twitter}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -106,7 +128,10 @@ const Details = () => {
|
|||||||
typeof config.social.dribbble !== 'undefined' && config.social.dribbble && (
|
typeof config.social.dribbble !== 'undefined' && config.social.dribbble && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<CgDribbble className="mr-2"/>
|
<CgDribbble className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://dribbble.com/${config.social.dribbble}`}
|
href={`https://dribbble.com/${config.social.dribbble}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -115,6 +140,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.dribbble}
|
{config.social.dribbble}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -123,7 +149,10 @@ const Details = () => {
|
|||||||
typeof config.social.behance !== 'undefined' && config.social.behance && (
|
typeof config.social.behance !== 'undefined' && config.social.behance && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<FaBehanceSquare className="mr-2"/>
|
<FaBehanceSquare className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://www.behance.net/${config.social.behance}`}
|
href={`https://www.behance.net/${config.social.behance}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -132,6 +161,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.behance}
|
{config.social.behance}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -140,7 +170,10 @@ const Details = () => {
|
|||||||
typeof config.social.facebook !== 'undefined' && config.social.facebook && (
|
typeof config.social.facebook !== 'undefined' && config.social.facebook && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<FaFacebook className="mr-2"/>
|
<FaFacebook className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://www.facebook.com/${config.social.facebook}`}
|
href={`https://www.facebook.com/${config.social.facebook}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -149,6 +182,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.facebook}
|
{config.social.facebook}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -157,7 +191,10 @@ const Details = () => {
|
|||||||
typeof config.social.medium !== 'undefined' && config.social.medium && (
|
typeof config.social.medium !== 'undefined' && config.social.medium && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<AiFillMediumSquare className="mr-2"/>
|
<AiFillMediumSquare className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://medium.com/@${config.social.medium}`}
|
href={`https://medium.com/@${config.social.medium}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -166,6 +203,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.medium}
|
{config.social.medium}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -174,7 +212,10 @@ const Details = () => {
|
|||||||
typeof config.social.devto !== 'undefined' && config.social.devto && (
|
typeof config.social.devto !== 'undefined' && config.social.devto && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<FaDev className="mr-2"/>
|
<FaDev className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`https://dev.to/${config.social.devto}`}
|
href={`https://dev.to/${config.social.devto}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -183,6 +224,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.devto}
|
{config.social.devto}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -191,7 +233,10 @@ const Details = () => {
|
|||||||
typeof config.social.website !== 'undefined' && config.social.website && (
|
typeof config.social.website !== 'undefined' && config.social.website && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<FaGlobe className="mr-2"/>
|
<FaGlobe className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`${config.social.website}`}
|
href={`${config.social.website}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -200,6 +245,27 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.website}
|
{config.social.website}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
typeof config.social.phone !== 'undefined' && config.social.phone && (
|
||||||
|
<li>
|
||||||
|
<span>
|
||||||
|
<div>
|
||||||
|
<RiPhoneFill className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
href={`tel:${config.social.phone}`}
|
||||||
|
rel="noreferrer"
|
||||||
|
className="text-base-content-important"
|
||||||
|
>
|
||||||
|
{config.social.phone}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -208,7 +274,10 @@ const Details = () => {
|
|||||||
typeof config.social.email !== 'undefined' && config.social.email && (
|
typeof config.social.email !== 'undefined' && config.social.email && (
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<MdMail className="mr-2"/>
|
<MdMail className="mr-2"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
href={`mailto:${config.social.email}`}
|
href={`mailto:${config.social.email}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -217,6 +286,7 @@ const Details = () => {
|
|||||||
>
|
>
|
||||||
{config.social.email}
|
{config.social.email}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -230,4 +300,8 @@ const Details = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Details.propTypes = {
|
||||||
|
profile: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
export default Details;
|
export default Details;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import { useSelector } from "react-redux";
|
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
import { GoPrimitiveDot } from 'react-icons/go';
|
import { GoPrimitiveDot } from 'react-icons/go';
|
||||||
import { skeleton } from "../helpers/utils";
|
import { skeleton } from "../helpers/utils";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { LoadingContext } from "../contexts/LoadingContext";
|
||||||
|
|
||||||
const Education = () => {
|
const Education = () => {
|
||||||
const loading = useSelector(state => state.loading);
|
const [loading] = useContext(LoadingContext);
|
||||||
|
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
@@ -42,7 +43,7 @@ const Education = () => {
|
|||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<ul className="menu row-span-3 bg-base-100 text-base-content">
|
<ul className="menu row-span-3 bg-base-100 text-base-content">
|
||||||
<li>
|
<li>
|
||||||
<div className="pb-0-important mx-5">
|
<div className="pb-0-important mx-3">
|
||||||
<h5 className="card-title">
|
<h5 className="card-title">
|
||||||
{
|
{
|
||||||
loading ? skeleton({width: 'w-32', height: 'h-8'}) : (
|
loading ? skeleton({width: 'w-32', height: 'h-8'}) : (
|
||||||
@@ -57,7 +58,9 @@ const Education = () => {
|
|||||||
config.education.map((item, index) => (
|
config.education.map((item, index) => (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<GoPrimitiveDot className="mr-2 opacity-40"/>
|
<GoPrimitiveDot className="mr-2 opacity-40"/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="block justify-between">
|
<div className="block justify-between">
|
||||||
<div className="font-medium opacity-70">
|
<div className="font-medium opacity-70">
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { useSelector } from "react-redux";
|
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
import { GoPrimitiveDot } from 'react-icons/go';
|
import { GoPrimitiveDot } from 'react-icons/go';
|
||||||
import { skeleton } from "../helpers/utils";
|
import { skeleton } from "../helpers/utils";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { LoadingContext } from "../contexts/LoadingContext";
|
||||||
|
|
||||||
const Experience = () => {
|
const Experience = () => {
|
||||||
const loading = useSelector(state => state.loading);
|
const [loading] = useContext(LoadingContext);
|
||||||
|
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
@@ -42,11 +43,13 @@ const Experience = () => {
|
|||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<ul className="menu row-span-3 bg-base-100 text-base-content">
|
<ul className="menu row-span-3 bg-base-100 text-base-content">
|
||||||
<li>
|
<li>
|
||||||
<div className="pb-0-important mx-5">
|
<div className="pb-0-important mx-3">
|
||||||
<h5 className="card-title">
|
<h5 className="card-title">
|
||||||
{loading ? skeleton({width: 'w-32', height: 'h-8'}) : (
|
{
|
||||||
|
loading ? skeleton({width: 'w-32', height: 'h-8'}) : (
|
||||||
<span className="opacity-70">Experience</span>
|
<span className="opacity-70">Experience</span>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@@ -55,7 +58,9 @@ const Experience = () => {
|
|||||||
config.experiences.map((experience, index) => (
|
config.experiences.map((experience, index) => (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
<span>
|
<span>
|
||||||
|
<div>
|
||||||
<GoPrimitiveDot className="mr-2 opacity-40"/>
|
<GoPrimitiveDot className="mr-2 opacity-40"/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="block justify-between">
|
<div className="block justify-between">
|
||||||
<div className="font-medium opacity-70">
|
<div className="font-medium opacity-70">
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment, useContext } from 'react';
|
||||||
import { Helmet } from "react-helmet-async";
|
import { Helmet } from "react-helmet-async";
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { isThemeDarkish } from '../helpers/utils';
|
import { isThemeDarkish } from '../helpers/utils';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { ThemeContext } from '../contexts/ThemeContext';
|
||||||
|
|
||||||
const MetaTags = () => {
|
const MetaTags = (props) => {
|
||||||
const profile = useSelector(state => state.profile);
|
const [theme] = useContext(ThemeContext);
|
||||||
const theme = useSelector(state => state.theme);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{
|
{
|
||||||
profile && (
|
props.profile && (
|
||||||
<Helmet>
|
<Helmet>
|
||||||
{
|
{
|
||||||
config.googleAnalytics.id && (
|
config.googleAnalytics?.id && (
|
||||||
<script async src={`https://www.googletagmanager.com/gtag/js?id=${config.googleAnalytics.id}`}></script>
|
<script async src={`https://www.googletagmanager.com/gtag/js?id=${config.googleAnalytics.id}`}></script>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
config.googleAnalytics.id && (
|
config.googleAnalytics?.id && (
|
||||||
<script>
|
<script>
|
||||||
{
|
{
|
||||||
`
|
`
|
||||||
@@ -33,25 +33,25 @@ const MetaTags = () => {
|
|||||||
</script>
|
</script>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<title>Portfolio of {profile.name}</title>
|
<title>Portfolio of {props.profile.name}</title>
|
||||||
<meta name="theme-color" content={isThemeDarkish(theme) ? '#000000' : '#ffffff'}/>
|
<meta name="theme-color" content={isThemeDarkish(theme) ? '#000000' : '#ffffff'}/>
|
||||||
|
|
||||||
<meta name="description" content={profile.bio} />
|
<meta name="description" content={props.profile.bio} />
|
||||||
|
|
||||||
<meta itemprop="name" content={`Portfolio of ${profile.name}`} />
|
<meta itemprop="name" content={`Portfolio of ${props.profile.name}`} />
|
||||||
<meta itemprop="description" content={profile.bio} />
|
<meta itemprop="description" content={props.profile.bio} />
|
||||||
<meta itemprop="image" content={profile.avatar} />
|
<meta itemprop="image" content={props.profile.avatar} />
|
||||||
|
|
||||||
<meta property="og:url" content={typeof config.social.website !== 'undefined' ? config.social.website : ''} />
|
<meta property="og:url" content={typeof config.social.website !== 'undefined' ? config.social.website : ''} />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:title" content={`Portfolio of ${profile.name}`} />
|
<meta property="og:title" content={`Portfolio of ${props.profile.name}`} />
|
||||||
<meta property="og:description" content={profile.bio} />
|
<meta property="og:description" content={props.profile.bio} />
|
||||||
<meta property="og:image" content={profile.avatar} />
|
<meta property="og:image" content={props.profile.avatar} />
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content={`Portfolio of ${profile.name}`} />
|
<meta name="twitter:title" content={`Portfolio of ${props.profile.name}`} />
|
||||||
<meta name="twitter:description" content={profile.bio} />
|
<meta name="twitter:description" content={props.profile.bio} />
|
||||||
<meta name="twitter:image" content={profile.avatar} />
|
<meta name="twitter:image" content={props.profile.avatar} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -59,4 +59,8 @@ const MetaTags = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaTags.propTypes = {
|
||||||
|
profile: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
export default MetaTags;
|
export default MetaTags;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Fragment } from "react";
|
import { Fragment, useContext } from "react";
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
import { ga, languageColor, skeleton } from "../helpers/utils";
|
import { ga, languageColor, skeleton } from "../helpers/utils";
|
||||||
import { AiOutlineStar, AiOutlineFork } from 'react-icons/ai';
|
import { AiOutlineStar, AiOutlineFork } from 'react-icons/ai';
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { LoadingContext } from "../contexts/LoadingContext";
|
||||||
|
|
||||||
const Project = () => {
|
const Project = (props) => {
|
||||||
const loading = useSelector(state => state.loading);
|
const [loading] = useContext(LoadingContext);
|
||||||
const repo = useSelector(state => state.repo);
|
|
||||||
|
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
@@ -51,13 +51,13 @@ const Project = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderProjects = () => {
|
const renderProjects = () => {
|
||||||
return repo.map((item, index) => (
|
return props.repo.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
className="card shadow-lg compact bg-base-100 cursor-pointer"
|
className="card shadow-lg compact bg-base-100 cursor-pointer"
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
try {
|
try {
|
||||||
if (config.googleAnalytics.id) {
|
if (config.googleAnalytics?.id) {
|
||||||
ga.event({
|
ga.event({
|
||||||
action: "Click project",
|
action: "Click project",
|
||||||
params: {
|
params: {
|
||||||
@@ -146,7 +146,7 @@ const Project = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col-span-2">
|
<div className="col-span-2">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
{(loading || !repo) ? renderSkeleton() : renderProjects()}
|
{(loading || !props.repo) ? renderSkeleton() : renderProjects()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -155,4 +155,8 @@ const Project = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Project.propTypes = {
|
||||||
|
repo: PropTypes.array
|
||||||
|
}
|
||||||
|
|
||||||
export default Project;
|
export default Project;
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useSelector } from "react-redux";
|
import { useContext } from "react";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
import { LoadingContext } from "../contexts/LoadingContext";
|
||||||
import { skeleton } from "../helpers/utils";
|
import { skeleton } from "../helpers/utils";
|
||||||
|
|
||||||
const Skill = () => {
|
const Skill = () => {
|
||||||
const loading = useSelector(state => state.loading);
|
const [loading] = useContext(LoadingContext);
|
||||||
|
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
@@ -24,6 +25,15 @@ const Skill = () => {
|
|||||||
(typeof config.skills !== 'undefined' && config.skills.length !== 0) && (
|
(typeof config.skills !== 'undefined' && config.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">
|
||||||
|
<h5 className="card-title">
|
||||||
|
{
|
||||||
|
loading ? skeleton({width: 'w-32', height: 'h-8'}) : (
|
||||||
|
<span className="opacity-70">Tech Stack</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
<div className="p-3 flow-root">
|
<div className="p-3 flow-root">
|
||||||
<div className="-m-1 flex flex-wrap">
|
<div className="-m-1 flex flex-wrap">
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
import { useDispatch, useSelector } from 'react-redux';
|
|
||||||
import { setTheme } from '../store/slices/themeSlice';
|
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { skeleton } from '../helpers/utils';
|
import { skeleton } from '../helpers/utils';
|
||||||
import { AiOutlineControl } from 'react-icons/ai';
|
import { AiOutlineControl } from 'react-icons/ai';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { ThemeContext } from '../contexts/ThemeContext';
|
||||||
|
import { LoadingContext } from '../contexts/LoadingContext';
|
||||||
|
|
||||||
const ThemeChanger = () => {
|
const ThemeChanger = () => {
|
||||||
const dispatch = useDispatch();
|
const [theme, setTheme] = useContext(ThemeContext);
|
||||||
const theme = useSelector(state => state.theme);
|
const [loading] = useContext(LoadingContext);
|
||||||
const loading = useSelector(state => state.loading);
|
|
||||||
|
|
||||||
const changeTheme = (e, selectedTheme) => {
|
const changeTheme = (e, selectedTheme) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
dispatch(setTheme(selectedTheme));
|
document.querySelector('html').setAttribute('data-theme', selectedTheme);
|
||||||
|
localStorage.setItem('ezprofile-theme', selectedTheme);
|
||||||
|
|
||||||
|
setTheme(selectedTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card overflow-visible shadow-lg compact bg-base-100">
|
<div className="card overflow-visible shadow-lg compact bg-base-100">
|
||||||
<div className="flex-row items-center space-x-4 flex pl-8 pr-2 py-4">
|
<div className="flex-row items-center space-x-4 flex pl-6 pr-2 py-4">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h5 className="card-title">
|
<h5 className="card-title">
|
||||||
{
|
{
|
||||||
@@ -26,7 +29,9 @@ const ThemeChanger = () => {
|
|||||||
}
|
}
|
||||||
</h5>
|
</h5>
|
||||||
<span className="text-base-content text-opacity-40 capitalize text-sm">
|
<span className="text-base-content text-opacity-40 capitalize text-sm">
|
||||||
{loading ? skeleton({ width: 'w-16', height: 'h-5' }) : (theme === config.themeConfig.default ? 'Default' : theme)}
|
{
|
||||||
|
loading ? skeleton({ width: 'w-16', height: 'h-5' }) : (theme === config.themeConfig.default ? 'Default' : theme)
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-0">
|
<div className="flex-0">
|
||||||
@@ -45,10 +50,10 @@ const ThemeChanger = () => {
|
|||||||
<div tabIndex={0} className="mt-16 overflow-y-auto shadow-2xl top-px dropdown-content h-96 w-52 rounded-b-box bg-base-200 text-base-content">
|
<div tabIndex={0} className="mt-16 overflow-y-auto shadow-2xl top-px dropdown-content h-96 w-52 rounded-b-box bg-base-200 text-base-content">
|
||||||
<ul className="p-4 menu compact">
|
<ul className="p-4 menu compact">
|
||||||
{
|
{
|
||||||
config.themeConfig.themes.map((item, index) => (
|
[config.themeConfig.default, ...config.themeConfig.themes.filter(item => item !== config.themeConfig.default)].map((item, index) => (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
|
{/* eslint-disable-next-line */}
|
||||||
<a
|
<a
|
||||||
href="/"
|
|
||||||
onClick={(e) => changeTheme(e, item)}
|
onClick={(e) => changeTheme(e, item)}
|
||||||
className={`${theme === item ? 'active' : ''}`}
|
className={`${theme === item ? 'active' : ''}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module.exports = {
|
|||||||
limit: 8, // How many projects to display.
|
limit: 8, // How many projects to display.
|
||||||
exclude: {
|
exclude: {
|
||||||
forks: false, // Forked projects will not be displayed if set to true.
|
forks: false, // Forked projects will not be displayed if set to true.
|
||||||
projects: [] // These projects will not be displayed. example: ['my-project1', 'my-project2']
|
projects: ['laravel-ecommerce'] // These projects will not be displayed. example: ['my-project1', 'my-project2']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
social: {
|
social: {
|
||||||
@@ -16,20 +16,20 @@ module.exports = {
|
|||||||
dribbble: '',
|
dribbble: '',
|
||||||
behance: '',
|
behance: '',
|
||||||
medium: '',
|
medium: '',
|
||||||
devto: '',
|
devto: 'arifszn',
|
||||||
website: 'https://arifszn.github.io',
|
website: 'https://arifszn.github.io',
|
||||||
email: 'contact@arifszn.com'
|
phone: '',
|
||||||
|
email: 'arifulalamszn@gmail.com'
|
||||||
},
|
},
|
||||||
skills: [
|
skills: [
|
||||||
'PHP',
|
'PHP',
|
||||||
'Laravel',
|
'Laravel',
|
||||||
'JavaScript',
|
'JavaScript',
|
||||||
'React.js',
|
'React.js',
|
||||||
'Vue.js',
|
|
||||||
'Node.js',
|
'Node.js',
|
||||||
'Jquery',
|
|
||||||
'MySQL',
|
'MySQL',
|
||||||
'Git',
|
'Git',
|
||||||
|
'Docker',
|
||||||
'CSS',
|
'CSS',
|
||||||
'Antd',
|
'Antd',
|
||||||
'Tailwind',
|
'Tailwind',
|
||||||
@@ -38,12 +38,12 @@ module.exports = {
|
|||||||
experiences: [
|
experiences: [
|
||||||
{
|
{
|
||||||
company: 'Monstarlab Bangladesh',
|
company: 'Monstarlab Bangladesh',
|
||||||
position: 'Software Engineer',
|
position: 'Backend Engineer II',
|
||||||
from: 'September 2021',
|
from: 'September 2021',
|
||||||
to: 'Present'
|
to: 'Present'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
company: 'Orangetoolz - My Offer 360 Degree',
|
company: 'Orangetoolz',
|
||||||
position: 'Jr. Full Stack Engineer',
|
position: 'Jr. Full Stack Engineer',
|
||||||
from: 'July 2019',
|
from: 'July 2019',
|
||||||
to: 'August 2021'
|
to: 'August 2021'
|
||||||
@@ -82,8 +82,12 @@ module.exports = {
|
|||||||
limit: 3 // How many posts to display. Max is 10.
|
limit: 3 // How many posts to display. Max is 10.
|
||||||
},
|
},
|
||||||
googleAnalytics: {
|
googleAnalytics: {
|
||||||
// GA3 tracking id/GA4 tag id
|
// GA3 tracking id/GA4 tag id UA-XXXXXXXXX-X | G-XXXXXXXXXX
|
||||||
id: '' // UA-XXXXXXXXX-X | G-XXXXXXXXXX
|
id: 'G-WLLB5E14M6' // Please remove this and use your own tag id or keep it empty
|
||||||
|
},
|
||||||
|
hotjar: {
|
||||||
|
id: '2617601', // Please remove this and use your own id or keep it empty
|
||||||
|
snippetVersion : 6
|
||||||
},
|
},
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
default: 'light',
|
default: 'light',
|
||||||
|
|||||||
15
src/contexts/LoadingContext.js
Normal file
15
src/contexts/LoadingContext.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { createContext, useState } from "react";
|
||||||
|
|
||||||
|
const initialValue = true;
|
||||||
|
|
||||||
|
export const LoadingContext = createContext();
|
||||||
|
|
||||||
|
export const LoadingProvider = (props) => {
|
||||||
|
const [loading, setLoading] = useState(initialValue);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadingContext.Provider value={[loading, setLoading]}>
|
||||||
|
{props.children}
|
||||||
|
</LoadingContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
src/contexts/ThemeContext.js
Normal file
16
src/contexts/ThemeContext.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { createContext, useState } from "react";
|
||||||
|
import { getInitialTheme } from "../helpers/utils";
|
||||||
|
|
||||||
|
const initialValue = getInitialTheme();
|
||||||
|
|
||||||
|
export const ThemeContext = createContext();
|
||||||
|
|
||||||
|
export const ThemeProvider = (props) => {
|
||||||
|
const [theme, setTheme] = useState(initialValue);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={[theme, setTheme]}>
|
||||||
|
{props.children}
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import config from "../config";
|
import config from "../config";
|
||||||
import colors from './colors.json';
|
import colors from './colors.json';
|
||||||
|
import { hotjar } from 'react-hotjar';
|
||||||
|
|
||||||
export const getThemeValue = () => {
|
export const getInitialTheme = () => {
|
||||||
if (config.themeConfig.disableSwitch) {
|
if (config.themeConfig.disableSwitch) {
|
||||||
return config.themeConfig.default;
|
return config.themeConfig.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localStorage.hasOwnProperty('ezprofileTheme')) {
|
if (localStorage.hasOwnProperty('ezprofile-theme')) {
|
||||||
let theme = localStorage.getItem('ezprofileTheme');
|
let theme = localStorage.getItem('ezprofile-theme');
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,3 +69,11 @@ export const isThemeDarkish = (theme) => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const setupHotjar = () => {
|
||||||
|
if (config.hotjar?.id) {
|
||||||
|
let snippetVersion = config.hotjar?.snippetVersion ? config.hotjar?.snippetVersion : 6;
|
||||||
|
|
||||||
|
hotjar.initialize(config.hotjar.id, snippetVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
@use "sass:meta";
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
* {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||||
@@ -26,7 +32,6 @@ body {
|
|||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
--z-primary: red;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
@@ -34,10 +39,6 @@ code {
|
|||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
.text-base-content-important {
|
.text-base-content-important {
|
||||||
color: hsla(var(--bc) / var(--tw-text-opacity)) !important;
|
color: hsla(var(--bc) / var(--tw-text-opacity)) !important;
|
||||||
}
|
}
|
||||||
14
src/index.js
14
src/index.js
@@ -1,21 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.scss';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import { Provider } from 'react-redux';
|
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals';
|
||||||
import { store } from './store/store';
|
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
|
import { ThemeProvider } from './contexts/ThemeContext';
|
||||||
|
import { LoadingProvider } from './contexts/LoadingContext';
|
||||||
|
import { setupHotjar } from './helpers/utils';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<Provider store={store}>
|
<ThemeProvider>
|
||||||
|
<LoadingProvider>
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<App/>
|
<App/>
|
||||||
</HelmetProvider>
|
</HelmetProvider>
|
||||||
</Provider>
|
</LoadingProvider>
|
||||||
|
</ThemeProvider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
|
||||||
reportWebVitals();
|
reportWebVitals();
|
||||||
|
setupHotjar();
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
|
||||||
|
|
||||||
const initialState = true;
|
|
||||||
|
|
||||||
export const loadingSlice = createSlice({
|
|
||||||
name: 'loading',
|
|
||||||
initialState: initialState,
|
|
||||||
reducers: {
|
|
||||||
setLoading: (state, action) => {
|
|
||||||
state = action.payload;
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export const { setLoading } = loadingSlice.actions;
|
|
||||||
|
|
||||||
export default loadingSlice.reducer;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
|
||||||
|
|
||||||
const initialState = null;
|
|
||||||
|
|
||||||
export const profileSlice = createSlice({
|
|
||||||
name: 'profile',
|
|
||||||
initialState: initialState,
|
|
||||||
reducers: {
|
|
||||||
setProfile: (state, action) => {
|
|
||||||
state = action.payload;
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export const { setProfile } = profileSlice.actions;
|
|
||||||
|
|
||||||
export default profileSlice.reducer;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
|
||||||
|
|
||||||
const initialState = null;
|
|
||||||
|
|
||||||
export const repoSlice = createSlice({
|
|
||||||
name: 'repo',
|
|
||||||
initialState: initialState,
|
|
||||||
reducers: {
|
|
||||||
setRepo: (state, action) => {
|
|
||||||
state = action.payload;
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export const { setRepo } = repoSlice.actions;
|
|
||||||
|
|
||||||
export default repoSlice.reducer;
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
|
||||||
import { getThemeValue } from '../../helpers/utils';
|
|
||||||
|
|
||||||
const initialState = getThemeValue();
|
|
||||||
|
|
||||||
export const themeSlice = createSlice({
|
|
||||||
name: 'theme',
|
|
||||||
initialState: initialState,
|
|
||||||
reducers: {
|
|
||||||
setTheme: (state, action) => {
|
|
||||||
state = action.payload;
|
|
||||||
|
|
||||||
document.querySelector('html').setAttribute('data-theme', state);
|
|
||||||
localStorage.setItem('ezprofileTheme', state);
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export const { setTheme } = themeSlice.actions;
|
|
||||||
|
|
||||||
export default themeSlice.reducer;
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { combineReducers, configureStore } from '@reduxjs/toolkit';
|
|
||||||
import loadingSlice from './slices/loadingSlice';
|
|
||||||
import profileSlice from './slices/profileSlice';
|
|
||||||
import repoSlice from './slices/repoSlice';
|
|
||||||
import themeSlice from './slices/themeSlice';
|
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
|
||||||
profile: profileSlice,
|
|
||||||
theme: themeSlice,
|
|
||||||
loading: loadingSlice,
|
|
||||||
repo: repoSlice,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const store = configureStore({
|
|
||||||
reducer: rootReducer
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user