mirror of
https://github.com/NohamR/gitprofile.git
synced 2026-05-25 20:00:25 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2021 MD. Ariful Alam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
95
README.md
95
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>
|
||||
</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).
|
||||
|
||||
✓ [21 Themes](#themes)\
|
||||
✓ [Google Analytics](#google-analytics)\
|
||||
✓ [Hotjar](#hotjar)\
|
||||
✓ [Meta Tags](#meta-tags)\
|
||||
✓ [Avatar and Bio](#avatar-and-bio)\
|
||||
✓ [Social Links](#social-links)\
|
||||
@@ -36,31 +37,40 @@ 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)**.
|
||||
|
||||
|
||||
|
||||
## 🛠 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.\
|
||||

|
||||
|
||||
- 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",
|
||||
}
|
||||
```
|
||||
|
||||
- Now commit to your **main** branch with your changes.
|
||||
- The CI/CD pipeline will publish your page at the gh-pages branch automatically.
|
||||
- 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 automatically update.
|
||||
|
||||
|
||||
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.
|
||||
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).
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
3. Change into your new directory.
|
||||
```sh
|
||||
cd ezprofile
|
||||
```
|
||||
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).
|
||||
|
||||
4. Install dependencies
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
5. Start the development server
|
||||
```sh
|
||||
npm start
|
||||
```
|
||||
|
||||
## 🎨 Customization
|
||||
|
||||
@@ -92,6 +102,7 @@ module.exports = {
|
||||
medium: '',
|
||||
devto: '',
|
||||
website: '',
|
||||
phone: '',
|
||||
email: ''
|
||||
},
|
||||
skills: [
|
||||
@@ -136,6 +147,10 @@ module.exports = {
|
||||
// GA3 tracking id/GA4 tag id
|
||||
id: '' // UA-XXXXXXXXX-X | G-XXXXXXXXXX
|
||||
},
|
||||
hotjar: {
|
||||
id: '',
|
||||
snippetVersion : 6
|
||||
},
|
||||
themeConfig: {
|
||||
default: 'light',
|
||||
|
||||
@@ -226,8 +241,22 @@ module.exports = {
|
||||
|
||||
Besides tracking visitors, ezFolio will track click events on projects and blog posts, and send them to Google Analytics.\
|
||||
<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
|
||||
|
||||
@@ -243,7 +272,7 @@ Your github avatar and bio will be displayed here.\
|
||||
|
||||
### 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
|
||||
// config.js
|
||||
module.exports = {
|
||||
@@ -257,6 +286,7 @@ module.exports = {
|
||||
medium: '',
|
||||
devto: '',
|
||||
website: 'https://arifszn.github.io',
|
||||
phone: '',
|
||||
email: ''
|
||||
},
|
||||
}
|
||||
@@ -375,35 +405,10 @@ module.exports = {
|
||||
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
|
||||
|
||||
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 or removing/changing the footer notice. However You are open to use this project by forking it and change any code necessary by giving attribute to the original author.
|
||||
|
||||
|
||||
## 💖 Support
|
||||
|
||||
4289
package-lock.json
generated
4289
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ezprofile",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "Kickstart your personal portfolio with Github Api and blog",
|
||||
"homepage": "https://arifszn.github.io/ezprofile",
|
||||
"private": true,
|
||||
@@ -12,12 +12,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@craco/craco": "^6.2.0",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"article-api": "^1.0.5",
|
||||
"axios": "^0.21.1",
|
||||
"axios": "^0.23.0",
|
||||
"daisyui": "^1.12.1",
|
||||
"gh-pages": "^3.2.3",
|
||||
"moment": "^2.29.1",
|
||||
@@ -25,8 +24,8 @@
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-helmet-async": "^1.1.0",
|
||||
"react-hotjar": "^3.0.1",
|
||||
"react-icons": "^4.2.0",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-scripts": "4.0.3",
|
||||
"sass": "^1.38.0",
|
||||
"web-vitals": "^1.0.1"
|
||||
|
||||
47
src/App.js
47
src/App.js
@@ -1,26 +1,25 @@
|
||||
import axios from "axios";
|
||||
import { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Fragment, useCallback, useContext, useEffect, useState } from "react";
|
||||
import AvatarCard from "./components/AvatarCard";
|
||||
import ErrorPage from "./components/ErrorPage";
|
||||
import ThemeChanger from "./components/ThemeChanger";
|
||||
import config from "./config";
|
||||
import moment from 'moment';
|
||||
import { setLoading } from "./store/slices/loadingSlice";
|
||||
import { setProfile } from "./store/slices/profileSlice";
|
||||
import Details from "./components/Details";
|
||||
import Skill from "./components/Skill";
|
||||
import Experience from "./components/Experience";
|
||||
import Education from "./components/Education";
|
||||
import Project from "./components/Project";
|
||||
import { setRepo } from "./store/slices/repoSlice";
|
||||
import Blog from "./components/Blog";
|
||||
import MetaTags from "./components/MetaTags";
|
||||
import { LoadingContext } from "./contexts/LoadingContext";
|
||||
import { ThemeContext } from "./contexts/ThemeContext";
|
||||
|
||||
function App() {
|
||||
const dispatch = useDispatch();
|
||||
const theme = useSelector(state => state.theme);
|
||||
|
||||
const [theme] = useContext(ThemeContext);
|
||||
const [, setLoading] = useContext(LoadingContext);
|
||||
const [profile, setProfile] = useState(null);
|
||||
const [repo, setRepo] = useState(null);
|
||||
const [error, setError] = useState(null);
|
||||
const [rateLimit, setRateLimit] = useState(null);
|
||||
|
||||
@@ -43,7 +42,7 @@ function App() {
|
||||
company: data.company ? data.company : ''
|
||||
}
|
||||
|
||||
dispatch(setProfile(profileData));
|
||||
setProfile(profileData);
|
||||
})
|
||||
.then(() => {
|
||||
let excludeRepo = ``;
|
||||
@@ -64,7 +63,7 @@ function App() {
|
||||
.then(response => {
|
||||
let data = response.data;
|
||||
|
||||
dispatch(setRepo(data.items));
|
||||
setRepo(data.items);
|
||||
})
|
||||
.catch((error) => {
|
||||
handleError(error);
|
||||
@@ -74,9 +73,9 @@ function App() {
|
||||
handleError(error);
|
||||
})
|
||||
.finally(() => {
|
||||
dispatch(setLoading(false));
|
||||
setLoading(false);
|
||||
});
|
||||
}, [dispatch])
|
||||
}, [setLoading])
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
@@ -91,7 +90,7 @@ function App() {
|
||||
});
|
||||
|
||||
if (error.response.status === 403) {
|
||||
setError(403);
|
||||
setError(429);
|
||||
} else if (error.response.status === 404) {
|
||||
setError(404);
|
||||
} else {
|
||||
@@ -104,7 +103,7 @@ function App() {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<MetaTags/>
|
||||
<MetaTags profile={profile}/>
|
||||
<div className="fade-in h-screen">
|
||||
|
||||
{
|
||||
@@ -112,7 +111,7 @@ function App() {
|
||||
<ErrorPage
|
||||
status={`${error}`}
|
||||
title={(error === 404) ? 'The Github Username is Incorrect' : (
|
||||
error === 403 ? 'Too Many Request.' : `Ops!!`
|
||||
error === 429 ? 'Too Many Requests.' : `Ops!!`
|
||||
)}
|
||||
subTitle={
|
||||
(error === 404) ? (
|
||||
@@ -120,7 +119,7 @@ function App() {
|
||||
Please provide correct github username in <code>src\config.js</code>
|
||||
</p>
|
||||
) : (
|
||||
error === 403 ? (
|
||||
error === 429 ? (
|
||||
<p>
|
||||
Oh no, you hit the{' '}
|
||||
<a
|
||||
@@ -144,20 +143,20 @@ function App() {
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
{
|
||||
!config.themeConfig.disableSwitch && (
|
||||
<ThemeChanger />
|
||||
<ThemeChanger/>
|
||||
)
|
||||
}
|
||||
<AvatarCard />
|
||||
<Details />
|
||||
<Skill />
|
||||
<Experience />
|
||||
<Education />
|
||||
<AvatarCard profile={profile}/>
|
||||
<Details profile={profile}/>
|
||||
<Skill/>
|
||||
<Experience/>
|
||||
<Education/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="lg:col-span-2 col-span-1">
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
<Project />
|
||||
<Blog />
|
||||
<Project repo={repo}/>
|
||||
<Blog/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { useSelector } from "react-redux";
|
||||
import { fallbackImage, skeleton } from "../helpers/utils";
|
||||
import LazyImage from "./LazyImage";
|
||||
import PropTypes from 'prop-types';
|
||||
import { useContext } from "react";
|
||||
import { LoadingContext } from "../contexts/LoadingContext";
|
||||
|
||||
const AvatarCard = () => {
|
||||
const profile = useSelector(state => state.profile);
|
||||
const loading = useSelector(state => state.loading);
|
||||
const AvatarCard = (props) => {
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
return (
|
||||
<div className="card shadow-lg compact bg-base-100">
|
||||
<div className="grid place-items-center py-8">
|
||||
{
|
||||
loading ? (
|
||||
(loading || !props.profile) ? (
|
||||
<div className="avatar opacity-90">
|
||||
<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">
|
||||
{
|
||||
<LazyImage
|
||||
src={profile.avatar ? profile.avatar : fallbackImage}
|
||||
alt={profile.name}
|
||||
src={props.profile.avatar ? props.profile.avatar : fallbackImage}
|
||||
alt={props.profile.name}
|
||||
placeholder={
|
||||
skeleton({
|
||||
width: 'w-full',
|
||||
@@ -42,19 +43,19 @@ const AvatarCard = () => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className="text-center mx-auto md:mx-8">
|
||||
<div className="text-center mx-auto px-8">
|
||||
<h5 className="font-bold text-2xl">
|
||||
{
|
||||
loading ? (
|
||||
(loading || !props.profile) ? (
|
||||
skeleton({ width: 'w-48', height: 'h-8' })
|
||||
) : <span className="opacity-70">{profile.name}</span>
|
||||
) : <span className="opacity-70">{props.profile.name}</span>
|
||||
}
|
||||
</h5>
|
||||
<div className="mt-3 text-base-content text-opacity-60">
|
||||
{
|
||||
loading ? (
|
||||
(loading || !props.profile) ? (
|
||||
skeleton({ width: 'w-48', height: 'h-5' })
|
||||
) : profile.bio
|
||||
) : props.profile.bio
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,4 +64,8 @@ const AvatarCard = () => {
|
||||
)
|
||||
}
|
||||
|
||||
AvatarCard.propTypes = {
|
||||
profile: PropTypes.object
|
||||
}
|
||||
|
||||
export default AvatarCard;
|
||||
@@ -1,9 +1,9 @@
|
||||
import { getDevtoArticle, getMediumArticle } from "article-api";
|
||||
import moment from "moment";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import { Fragment, useContext, useEffect, useState } from "react";
|
||||
import { CgHashtag } from 'react-icons/cg';
|
||||
import { useSelector } from "react-redux";
|
||||
import config from "../config";
|
||||
import { LoadingContext } from "../contexts/LoadingContext";
|
||||
import { ga, skeleton } from "../helpers/utils";
|
||||
import LazyImage from "./LazyImage";
|
||||
|
||||
@@ -23,7 +23,7 @@ const displaySection = () => {
|
||||
|
||||
const Blog = () => {
|
||||
const [articles, setArticles] = useState(null);
|
||||
const loading = useSelector(state => state.loading);
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (displaySection()) {
|
||||
@@ -141,7 +141,7 @@ const Blog = () => {
|
||||
{
|
||||
article.categories.map((category, index2) => (
|
||||
<div key={index2} className="flex text-sm mr-3 items-center opacity-50 font-bold font-mono">
|
||||
<CgHashtag />
|
||||
<span><CgHashtag /></span>
|
||||
<span>{category}</span>
|
||||
</div>
|
||||
))
|
||||
|
||||
@@ -3,14 +3,16 @@ import { AiFillGithub, AiFillMediumSquare } from 'react-icons/ai';
|
||||
import { SiTwitter } from 'react-icons/si';
|
||||
import { GrLinkedinOption } from 'react-icons/gr';
|
||||
import { CgDribbble } from 'react-icons/cg';
|
||||
import { RiPhoneFill } from 'react-icons/ri';
|
||||
import { FaBehanceSquare, FaBuilding, FaDev, FaFacebook, FaGlobe } from 'react-icons/fa';
|
||||
import { useSelector } from 'react-redux';
|
||||
import config from '../config';
|
||||
import { skeleton } from '../helpers/utils';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useContext } from 'react';
|
||||
import { LoadingContext } from '../contexts/LoadingContext';
|
||||
|
||||
const Details = () => {
|
||||
const profile = useSelector(state => state.profile);
|
||||
const loading = useSelector(state => state.loading);
|
||||
const Details = (props) => {
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
const renderSkeleton = () => {
|
||||
let array = [];
|
||||
@@ -33,31 +35,42 @@ const Details = () => {
|
||||
<div className="card-body">
|
||||
<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>
|
||||
<span>
|
||||
<MdLocationOn className="mr-2" />
|
||||
{profile.location}
|
||||
<div>
|
||||
<MdLocationOn className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
{props.profile.location}
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
{
|
||||
profile && profile.company && (
|
||||
props.profile.company && (
|
||||
<li>
|
||||
<span>
|
||||
<FaBuilding className="mr-2" />
|
||||
{profile.company}
|
||||
<div>
|
||||
<FaBuilding className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
{props.profile.company}
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
<li>
|
||||
<span>
|
||||
<AiFillGithub className="mr-2" />
|
||||
<div>
|
||||
<AiFillGithub className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://github.com/${config.github.username}`}
|
||||
target="_blank"
|
||||
@@ -66,13 +79,17 @@ const Details = () => {
|
||||
>
|
||||
{config.github.username}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
{
|
||||
typeof config.social.linkedin !== 'undefined' && config.social.linkedin && (
|
||||
<li>
|
||||
<span>
|
||||
<GrLinkedinOption className="mr-2" />
|
||||
<div>
|
||||
<GrLinkedinOption className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://www.linkedin.com/in/${config.social.linkedin}`}
|
||||
target="_blank"
|
||||
@@ -81,6 +98,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.linkedin}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -89,7 +107,10 @@ const Details = () => {
|
||||
typeof config.social.twitter !== 'undefined' && config.social.twitter && (
|
||||
<li>
|
||||
<span>
|
||||
<SiTwitter className="mr-2" />
|
||||
<div>
|
||||
<SiTwitter className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://twitter.com/${config.social.twitter}`}
|
||||
target="_blank"
|
||||
@@ -98,6 +119,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.twitter}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -106,7 +128,10 @@ const Details = () => {
|
||||
typeof config.social.dribbble !== 'undefined' && config.social.dribbble && (
|
||||
<li>
|
||||
<span>
|
||||
<CgDribbble className="mr-2" />
|
||||
<div>
|
||||
<CgDribbble className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://dribbble.com/${config.social.dribbble}`}
|
||||
target="_blank"
|
||||
@@ -115,6 +140,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.dribbble}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -123,7 +149,10 @@ const Details = () => {
|
||||
typeof config.social.behance !== 'undefined' && config.social.behance && (
|
||||
<li>
|
||||
<span>
|
||||
<FaBehanceSquare className="mr-2" />
|
||||
<div>
|
||||
<FaBehanceSquare className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://www.behance.net/${config.social.behance}`}
|
||||
target="_blank"
|
||||
@@ -132,6 +161,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.behance}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -140,7 +170,10 @@ const Details = () => {
|
||||
typeof config.social.facebook !== 'undefined' && config.social.facebook && (
|
||||
<li>
|
||||
<span>
|
||||
<FaFacebook className="mr-2" />
|
||||
<div>
|
||||
<FaFacebook className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://www.facebook.com/${config.social.facebook}`}
|
||||
target="_blank"
|
||||
@@ -149,6 +182,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.facebook}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -157,7 +191,10 @@ const Details = () => {
|
||||
typeof config.social.medium !== 'undefined' && config.social.medium && (
|
||||
<li>
|
||||
<span>
|
||||
<AiFillMediumSquare className="mr-2" />
|
||||
<div>
|
||||
<AiFillMediumSquare className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://medium.com/@${config.social.medium}`}
|
||||
target="_blank"
|
||||
@@ -166,6 +203,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.medium}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -174,7 +212,10 @@ const Details = () => {
|
||||
typeof config.social.devto !== 'undefined' && config.social.devto && (
|
||||
<li>
|
||||
<span>
|
||||
<FaDev className="mr-2" />
|
||||
<div>
|
||||
<FaDev className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`https://dev.to/${config.social.devto}`}
|
||||
target="_blank"
|
||||
@@ -183,6 +224,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.devto}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -191,7 +233,10 @@ const Details = () => {
|
||||
typeof config.social.website !== 'undefined' && config.social.website && (
|
||||
<li>
|
||||
<span>
|
||||
<FaGlobe className="mr-2" />
|
||||
<div>
|
||||
<FaGlobe className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`${config.social.website}`}
|
||||
target="_blank"
|
||||
@@ -200,6 +245,27 @@ const Details = () => {
|
||||
>
|
||||
{config.social.website}
|
||||
</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>
|
||||
</li>
|
||||
)
|
||||
@@ -208,7 +274,10 @@ const Details = () => {
|
||||
typeof config.social.email !== 'undefined' && config.social.email && (
|
||||
<li>
|
||||
<span>
|
||||
<MdMail className="mr-2" />
|
||||
<div>
|
||||
<MdMail className="mr-2"/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href={`mailto:${config.social.email}`}
|
||||
target="_blank"
|
||||
@@ -217,6 +286,7 @@ const Details = () => {
|
||||
>
|
||||
{config.social.email}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
@@ -230,4 +300,8 @@ const Details = () => {
|
||||
)
|
||||
}
|
||||
|
||||
Details.propTypes = {
|
||||
profile: PropTypes.object
|
||||
}
|
||||
|
||||
export default Details;
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useSelector } from "react-redux";
|
||||
import config from "../config";
|
||||
import { GoPrimitiveDot } from 'react-icons/go';
|
||||
import { skeleton } from "../helpers/utils";
|
||||
import { useContext } from "react";
|
||||
import { LoadingContext } from "../contexts/LoadingContext";
|
||||
|
||||
const Education = () => {
|
||||
const loading = useSelector(state => state.loading);
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
const renderSkeleton = () => {
|
||||
let array = [];
|
||||
@@ -42,7 +43,7 @@ const Education = () => {
|
||||
<div className="card-body">
|
||||
<ul className="menu row-span-3 bg-base-100 text-base-content">
|
||||
<li>
|
||||
<div className="pb-0-important mx-5">
|
||||
<div className="pb-0-important mx-3">
|
||||
<h5 className="card-title">
|
||||
{
|
||||
loading ? skeleton({width: 'w-32', height: 'h-8'}) : (
|
||||
@@ -57,7 +58,9 @@ const Education = () => {
|
||||
config.education.map((item, index) => (
|
||||
<li key={index}>
|
||||
<span>
|
||||
<div>
|
||||
<GoPrimitiveDot className="mr-2 opacity-40"/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="block justify-between">
|
||||
<div className="font-medium opacity-70">
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useSelector } from "react-redux";
|
||||
import config from "../config";
|
||||
import { GoPrimitiveDot } from 'react-icons/go';
|
||||
import { skeleton } from "../helpers/utils";
|
||||
import { useContext } from "react";
|
||||
import { LoadingContext } from "../contexts/LoadingContext";
|
||||
|
||||
const Experience = () => {
|
||||
const loading = useSelector(state => state.loading);
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
const renderSkeleton = () => {
|
||||
let array = [];
|
||||
@@ -42,11 +43,13 @@ const Experience = () => {
|
||||
<div className="card-body">
|
||||
<ul className="menu row-span-3 bg-base-100 text-base-content">
|
||||
<li>
|
||||
<div className="pb-0-important mx-5">
|
||||
<div className="pb-0-important mx-3">
|
||||
<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>
|
||||
)}
|
||||
)
|
||||
}
|
||||
</h5>
|
||||
</div>
|
||||
</li>
|
||||
@@ -55,7 +58,9 @@ const Experience = () => {
|
||||
config.experiences.map((experience, index) => (
|
||||
<li key={index}>
|
||||
<span>
|
||||
<div>
|
||||
<GoPrimitiveDot className="mr-2 opacity-40"/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="block justify-between">
|
||||
<div className="font-medium opacity-70">
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React, { Fragment, useContext } from 'react';
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useSelector } from 'react-redux';
|
||||
import config from '../config';
|
||||
import { isThemeDarkish } from '../helpers/utils';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ThemeContext } from '../contexts/ThemeContext';
|
||||
|
||||
const MetaTags = () => {
|
||||
const profile = useSelector(state => state.profile);
|
||||
const theme = useSelector(state => state.theme);
|
||||
const MetaTags = (props) => {
|
||||
const [theme] = useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{
|
||||
profile && (
|
||||
props.profile && (
|
||||
<Helmet>
|
||||
{
|
||||
config.googleAnalytics.id && (
|
||||
@@ -33,25 +33,25 @@ const MetaTags = () => {
|
||||
</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="description" content={profile.bio} />
|
||||
<meta name="description" content={props.profile.bio} />
|
||||
|
||||
<meta itemprop="name" content={`Portfolio of ${profile.name}`} />
|
||||
<meta itemprop="description" content={profile.bio} />
|
||||
<meta itemprop="image" content={profile.avatar} />
|
||||
<meta itemprop="name" content={`Portfolio of ${props.profile.name}`} />
|
||||
<meta itemprop="description" content={props.profile.bio} />
|
||||
<meta itemprop="image" content={props.profile.avatar} />
|
||||
|
||||
<meta property="og:url" content={typeof config.social.website !== 'undefined' ? config.social.website : ''} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content={`Portfolio of ${profile.name}`} />
|
||||
<meta property="og:description" content={profile.bio} />
|
||||
<meta property="og:image" content={profile.avatar} />
|
||||
<meta property="og:title" content={`Portfolio of ${props.profile.name}`} />
|
||||
<meta property="og:description" content={props.profile.bio} />
|
||||
<meta property="og:image" content={props.profile.avatar} />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={`Portfolio of ${profile.name}`} />
|
||||
<meta name="twitter:description" content={profile.bio} />
|
||||
<meta name="twitter:image" content={profile.avatar} />
|
||||
<meta name="twitter:title" content={`Portfolio of ${props.profile.name}`} />
|
||||
<meta name="twitter:description" content={props.profile.bio} />
|
||||
<meta name="twitter:image" content={props.profile.avatar} />
|
||||
</Helmet>
|
||||
)
|
||||
}
|
||||
@@ -59,4 +59,8 @@ const MetaTags = () => {
|
||||
)
|
||||
}
|
||||
|
||||
MetaTags.propTypes = {
|
||||
profile: PropTypes.object
|
||||
}
|
||||
|
||||
export default MetaTags;
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Fragment } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Fragment, useContext } from "react";
|
||||
import { ga, languageColor, skeleton } from "../helpers/utils";
|
||||
import { AiOutlineStar, AiOutlineFork } from 'react-icons/ai';
|
||||
import config from "../config";
|
||||
import PropTypes from 'prop-types';
|
||||
import { LoadingContext } from "../contexts/LoadingContext";
|
||||
|
||||
const Project = () => {
|
||||
const loading = useSelector(state => state.loading);
|
||||
const repo = useSelector(state => state.repo);
|
||||
const Project = (props) => {
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
const renderSkeleton = () => {
|
||||
let array = [];
|
||||
@@ -51,7 +51,7 @@ const Project = () => {
|
||||
}
|
||||
|
||||
const renderProjects = () => {
|
||||
return repo.map((item, index) => (
|
||||
return props.repo.map((item, index) => (
|
||||
<div
|
||||
className="card shadow-lg compact bg-base-100 cursor-pointer"
|
||||
key={index}
|
||||
@@ -146,7 +146,7 @@ const Project = () => {
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{(loading || !repo) ? renderSkeleton() : renderProjects()}
|
||||
{(loading || !props.repo) ? renderSkeleton() : renderProjects()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -155,4 +155,8 @@ const Project = () => {
|
||||
)
|
||||
}
|
||||
|
||||
Project.propTypes = {
|
||||
repo: PropTypes.array
|
||||
}
|
||||
|
||||
export default Project;
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useSelector } from "react-redux";
|
||||
import { useContext } from "react";
|
||||
import config from "../config";
|
||||
import { LoadingContext } from "../contexts/LoadingContext";
|
||||
import { skeleton } from "../helpers/utils";
|
||||
|
||||
const Skill = () => {
|
||||
const loading = useSelector(state => state.loading);
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
const renderSkeleton = () => {
|
||||
let array = [];
|
||||
@@ -24,6 +25,15 @@ const Skill = () => {
|
||||
(typeof config.skills !== 'undefined' && config.skills.length !== 0) && (
|
||||
<div className="card shadow-lg compact bg-base-100">
|
||||
<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="-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 { skeleton } from '../helpers/utils';
|
||||
import { AiOutlineControl } from 'react-icons/ai';
|
||||
import { useContext } from 'react';
|
||||
import { ThemeContext } from '../contexts/ThemeContext';
|
||||
import { LoadingContext } from '../contexts/LoadingContext';
|
||||
|
||||
const ThemeChanger = () => {
|
||||
const dispatch = useDispatch();
|
||||
const theme = useSelector(state => state.theme);
|
||||
const loading = useSelector(state => state.loading);
|
||||
const [theme, setTheme] = useContext(ThemeContext);
|
||||
const [loading] = useContext(LoadingContext);
|
||||
|
||||
const changeTheme = (e, selectedTheme) => {
|
||||
e.preventDefault();
|
||||
dispatch(setTheme(selectedTheme));
|
||||
document.querySelector('html').setAttribute('data-theme', selectedTheme);
|
||||
localStorage.setItem('ezprofileTheme', selectedTheme);
|
||||
|
||||
setTheme(selectedTheme);
|
||||
}
|
||||
|
||||
return (
|
||||
<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">
|
||||
<h5 className="card-title">
|
||||
{
|
||||
@@ -26,7 +29,9 @@ const ThemeChanger = () => {
|
||||
}
|
||||
</h5>
|
||||
<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>
|
||||
</div>
|
||||
<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">
|
||||
<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}>
|
||||
{/* eslint-disable-next-line */}
|
||||
<a
|
||||
href="/"
|
||||
onClick={(e) => changeTheme(e, item)}
|
||||
className={`${theme === item ? 'active' : ''}`}
|
||||
>
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = {
|
||||
medium: '',
|
||||
devto: '',
|
||||
website: 'https://arifszn.github.io',
|
||||
phone: '',
|
||||
email: 'contact@arifszn.com'
|
||||
},
|
||||
skills: [
|
||||
@@ -30,6 +31,7 @@ module.exports = {
|
||||
'Jquery',
|
||||
'MySQL',
|
||||
'Git',
|
||||
'Docker',
|
||||
'CSS',
|
||||
'Antd',
|
||||
'Tailwind',
|
||||
@@ -38,7 +40,7 @@ module.exports = {
|
||||
experiences: [
|
||||
{
|
||||
company: 'Monstarlab Bangladesh',
|
||||
position: 'Software Engineer',
|
||||
position: 'Backend Engineer',
|
||||
from: 'September 2021',
|
||||
to: 'Present'
|
||||
},
|
||||
@@ -79,11 +81,15 @@ module.exports = {
|
||||
// Display blog posts from your medium or dev.to account. (Optional)
|
||||
source: 'dev.to', // medium | dev.to
|
||||
username: 'arifszn',
|
||||
limit: 3 // How many posts to display. Max is 10.
|
||||
limit: 2 // How many posts to display. Max is 10.
|
||||
},
|
||||
googleAnalytics: {
|
||||
// GA3 tracking id/GA4 tag id
|
||||
id: '' // UA-XXXXXXXXX-X | G-XXXXXXXXXX
|
||||
// GA3 tracking id/GA4 tag id UA-XXXXXXXXX-X | G-XXXXXXXXXX
|
||||
id: 'G-WLLB5E14M6' // Please remove this and use your own tag id
|
||||
},
|
||||
hotjar: {
|
||||
id: '2617601', // Please remove this and use your own id
|
||||
snippetVersion : 6
|
||||
},
|
||||
themeConfig: {
|
||||
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,7 +1,8 @@
|
||||
import config from "../config";
|
||||
import colors from './colors.json';
|
||||
import { hotjar } from 'react-hotjar';
|
||||
|
||||
export const getThemeValue = () => {
|
||||
export const getInitialTheme = () => {
|
||||
if (config.themeConfig.disableSwitch) {
|
||||
return config.themeConfig.default;
|
||||
}
|
||||
@@ -68,3 +69,11 @@ export const isThemeDarkish = (theme) => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const setupHotjar = () => {
|
||||
if (config.hotjar?.id) {
|
||||
let snippetVersion = config.hotjar?.snippetVersion ? config.hotjar?.snippetVersion : 6;
|
||||
|
||||
hotjar.initialize(config.hotjar.id, snippetVersion);
|
||||
}
|
||||
}
|
||||
12
src/index.js
12
src/index.js
@@ -2,20 +2,24 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.scss';
|
||||
import App from './App';
|
||||
import { Provider } from 'react-redux';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import { store } from './store/store';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
import { ThemeProvider } from './contexts/ThemeContext';
|
||||
import { LoadingProvider } from './contexts/LoadingContext';
|
||||
import { setupHotjar } from './helpers/utils';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<ThemeProvider>
|
||||
<LoadingProvider>
|
||||
<HelmetProvider>
|
||||
<App/>
|
||||
</HelmetProvider>
|
||||
</Provider>
|
||||
</LoadingProvider>
|
||||
</ThemeProvider>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
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