├── .gitignore ├── src ├── data │ ├── index.js │ └── icons.js ├── utils │ ├── index.js │ ├── Input │ │ ├── input.css │ │ └── Input.jsx │ ├── Button │ │ ├── button.jsx │ │ └── button.css │ ├── pointer.jsx │ ├── Loading │ │ ├── Loading.jsx │ │ └── loading.css │ ├── functions.js │ ├── Hover │ │ ├── Hover.jsx │ │ └── hover.css │ ├── Loading2 │ │ ├── Loading.jsx │ │ └── loading.css │ ├── Cursor │ │ ├── cursor.css │ │ └── cursor.jsx │ └── Components.jsx ├── assets │ ├── bg_1.jpg │ ├── image1.jpg │ ├── image2.jpg │ ├── image3.jpg │ ├── people1.jpg │ ├── people2.jpg │ ├── people3.jpg │ ├── profile.png │ ├── project1.jpg │ ├── project2.jpg │ ├── project3.jpg │ ├── project4.jpg │ ├── project5.jpg │ ├── project6.jpg │ ├── faveicon1.ico │ ├── index.js │ └── quotes.svg ├── constant.js ├── Admin │ ├── components │ │ ├── Error.jsx │ │ ├── Loading.jsx │ │ ├── index.jsx │ │ ├── SubHeading.jsx │ │ ├── Heading.jsx │ │ ├── Table.jsx │ │ ├── Textarea.jsx │ │ ├── Navbar.jsx │ │ ├── Slider.jsx │ │ └── DropDown.jsx │ ├── pages │ │ ├── index.jsx │ │ ├── Blogs │ │ │ ├── Delete.jsx │ │ │ ├── View.jsx │ │ │ └── Blogs.jsx │ │ ├── Skills │ │ │ ├── Delete.jsx │ │ │ ├── View.jsx │ │ │ ├── Skills.jsx │ │ │ └── Create.jsx │ │ ├── Freelancing │ │ │ ├── Delete.jsx │ │ │ ├── View.jsx │ │ │ └── Freelancing.jsx │ │ ├── Resumes │ │ │ ├── Delete.jsx │ │ │ ├── View.jsx │ │ │ └── Resumes.jsx │ │ ├── Projects │ │ │ ├── Delete.jsx │ │ │ └── View.jsx │ │ ├── Services │ │ │ ├── Delete.jsx │ │ │ ├── View.jsx │ │ │ └── Services.jsx │ │ ├── Testimonials │ │ │ ├── Delete.jsx │ │ │ ├── View.jsx │ │ │ └── Testimonials.jsx │ │ └── Contact │ │ │ ├── View.jsx │ │ │ └── Contact.jsx │ └── Admin.jsx ├── User │ ├── components │ │ ├── index.jsx │ │ ├── Button.jsx │ │ ├── NavigationDots.jsx │ │ ├── MainHeading.jsx │ │ ├── SocialLinks.jsx │ │ ├── Input.jsx │ │ └── HeaderText.jsx │ ├── pages │ │ ├── Projects │ │ │ ├── pagination.css │ │ │ ├── Projects.jsx │ │ │ └── Project.jsx │ │ ├── Testimonials │ │ │ ├── testimonial.jsx │ │ │ ├── swiper.css │ │ │ └── TestimonialsCard.jsx │ │ ├── Resume │ │ │ └── ResumeCard.jsx │ │ ├── Skills │ │ │ ├── Skillbar.jsx │ │ │ └── Skills.jsx │ │ ├── index.jsx │ │ ├── Contact │ │ │ ├── ContactCard.jsx │ │ │ └── Contact.jsx │ │ ├── Auth │ │ │ ├── login.css │ │ │ ├── login.jsx │ │ │ └── Register.jsx │ │ ├── Services │ │ │ ├── ServiceCard.jsx │ │ │ ├── Services.jsx │ │ │ └── service.css │ │ ├── Account │ │ │ └── Account.jsx │ │ ├── Freelancing │ │ │ └── Confirm.jsx │ │ ├── Home │ │ │ └── Home.jsx │ │ ├── About │ │ │ └── About.jsx │ │ └── Blogs │ │ │ ├── Blogs.jsx │ │ │ └── BlogCard.jsx │ └── User.jsx ├── App.jsx ├── index.jsx ├── redux │ ├── actions │ │ ├── contact.js │ │ ├── general.js │ │ ├── user.js │ │ ├── blog.js │ │ ├── freelancing.js │ │ ├── skill.js │ │ ├── resume.js │ │ ├── service.js │ │ ├── project.js │ │ └── testimonial.js │ ├── reducers │ │ ├── general.js │ │ ├── contact.js │ │ ├── user.js │ │ ├── blog.js │ │ ├── skill.js │ │ ├── freelancing.js │ │ ├── resume.js │ │ ├── service.js │ │ ├── project.js │ │ └── testimonial.js │ ├── store.js │ └── api │ │ └── index.js ├── contexts │ └── ContextProvider.jsx └── index.css ├── postcss.config.js ├── vite.config.js ├── index.html ├── tailwind.config.js ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /src/data/index.js: -------------------------------------------------------------------------------- 1 | export { default as icons } from './icons' -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | export { default as Input } from './Input/Input' -------------------------------------------------------------------------------- /src/assets/bg_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/bg_1.jpg -------------------------------------------------------------------------------- /src/assets/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/image1.jpg -------------------------------------------------------------------------------- /src/assets/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/image2.jpg -------------------------------------------------------------------------------- /src/assets/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/image3.jpg -------------------------------------------------------------------------------- /src/assets/people1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/people1.jpg -------------------------------------------------------------------------------- /src/assets/people2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/people2.jpg -------------------------------------------------------------------------------- /src/assets/people3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/people3.jpg -------------------------------------------------------------------------------- /src/assets/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/profile.png -------------------------------------------------------------------------------- /src/assets/project1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/project1.jpg -------------------------------------------------------------------------------- /src/assets/project2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/project2.jpg -------------------------------------------------------------------------------- /src/assets/project3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/project3.jpg -------------------------------------------------------------------------------- /src/assets/project4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/project4.jpg -------------------------------------------------------------------------------- /src/assets/project5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/project5.jpg -------------------------------------------------------------------------------- /src/assets/project6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/project6.jpg -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /src/assets/faveicon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naumanch969/mern-orange-portfolio-client/HEAD/src/assets/faveicon1.ico -------------------------------------------------------------------------------- /src/utils/Input/input.css: -------------------------------------------------------------------------------- 1 | .inputBox input:focus~label, 2 | textarea:valid~label { 3 | transform: translateX(0px) translateY(-34px); 4 | } -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /src/constant.js: -------------------------------------------------------------------------------- 1 | export const baseURL = 'http://localhost:5000' 2 | // export const baseURL = 'https://naumanchportfolio.glitch.me' 3 | // export const baseURL = 'https://mern-orange-portfolio-server.vercel.app' -------------------------------------------------------------------------------- /src/Admin/components/Error.jsx: -------------------------------------------------------------------------------- 1 | 2 | const Error = ({ error }) => { 3 | 4 | 5 | return ( 6 |
7 |

{error}

8 |
9 | ) 10 | } 11 | 12 | export default Error; -------------------------------------------------------------------------------- /src/utils/Button/button.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './button.css' 3 | 4 | const Button = () => { 5 | return ( 6 |
7 | 8 | 9 | Button 10 | 11 | 12 | 13 |
14 | ) 15 | } 16 | 17 | export default Button -------------------------------------------------------------------------------- /src/User/components/index.jsx: -------------------------------------------------------------------------------- 1 | export { default as Navbar } from "./Navbar" 2 | export { default as MainHeading } from "./MainHeading" 3 | export { default as Button } from "./Button" 4 | export { default as HeaderText } from "./HeaderText" 5 | export { default as Input } from "./Input" 6 | 7 | export { default as NavigationDots } from "./NavigationDots" 8 | export { default as SocialLinks } from "./SocialLinks" -------------------------------------------------------------------------------- /src/User/pages/Projects/pagination.css: -------------------------------------------------------------------------------- 1 | .MuiPagination-ul>li>button { 2 | background-color: #222222; 3 | color: white; 4 | } 5 | 6 | .MuiButtonBase-root.MuiPaginationItem-root.MuiPaginationItem-sizeMedium.MuiPaginationItem-text.MuiPaginationItem-circular.Mui-selected.MuiPaginationItem-page.css-yuzg60-MuiButtonBase-root-MuiPaginationItem-root { 7 | background-color: #feb931; 8 | color: #ffffff; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/Admin/pages/index.jsx: -------------------------------------------------------------------------------- 1 | export { default as Resumes } from "./Resumes/Resumes" 2 | export { default as Services } from "./Services/Services" 3 | export { default as Skills } from "./Skills/Skills" 4 | export { default as Projects } from "./Projects/Projects" 5 | export { default as Blogs } from "./Blogs/Blogs" 6 | export { default as Testimonials } from "./Testimonials/Testimonials" 7 | export { default as Freelancing } from "./Freelancing/Freelancing" 8 | export { default as Contact } from "./Contact/Contact" -------------------------------------------------------------------------------- /src/Admin/components/Loading.jsx: -------------------------------------------------------------------------------- 1 | import { CircularProgress } from '@mui/material' 2 | 3 | const Loading = ({ title }) => { 4 | return ( 5 |
6 | 7 |

{title ? title : 'Fetching Data...'}

8 |
9 | ) 10 | } 11 | export default Loading; -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useStateContext } from "./contexts/ContextProvider" 2 | 3 | import Admin from "./Admin/Admin" 4 | import User from "./User/User" 5 | 6 | const App = () => { 7 | 8 | const { mode } = useStateContext() 9 | 10 | return ( 11 |
12 | 13 | 14 | { 15 | mode == 'admin' 16 | ? 17 | 18 | : 19 | 20 | } 21 | 22 |
23 | ); 24 | }; 25 | 26 | export default App; -------------------------------------------------------------------------------- /src/Admin/components/index.jsx: -------------------------------------------------------------------------------- 1 | export { default as Sidebar } from "./Sidebar" 2 | export { default as Navbar } from "./Navbar" 3 | export { default as Heading } from "./Heading" 4 | export { default as SubHeading } from "./SubHeading" 5 | export { default as Textarea } from "./Textarea" 6 | export { default as Loading } from "./Loading" 7 | export { default as Error } from "./Error" 8 | export { default as Slider } from "./Slider" 9 | export { default as DropDown } from "./DropDown" 10 | export { default as Table } from "./Table" -------------------------------------------------------------------------------- /src/User/pages/Testimonials/testimonial.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState } from 'react'; 2 | import { Swiper, SwiperSlide } from 'swiper/react'; 3 | import 'swiper/css'; 4 | import 'swiper/css/effect-coverflow'; 5 | import 'swiper/css/pagination'; 6 | import './testimonial.css'; 7 | import { EffectCoverflow } from 'swiper/modules'; 8 | 9 | const testimonials = () => { 10 | return ( 11 |
12 | 13 |
14 | ); 15 | } 16 | 17 | 18 | export default testimonials -------------------------------------------------------------------------------- /src/User/components/Button.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'react-scroll' 2 | 3 | const Button = ({ to, text, color, background, onClick, border, disabled }) => { 4 | 5 | return ( 6 | 7 | {text} 8 | 9 | ) 10 | } 11 | 12 | export default Button; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Nauman Chaudhry 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/index.js: -------------------------------------------------------------------------------- 1 | export { default as bg } from "./bg_1.jpg" 2 | export { default as blog1 } from "./image1.jpg" 3 | export { default as blog2 } from "./image2.jpg" 4 | export { default as blog3 } from "./image3.jpg" 5 | export { default as project1 } from "./project1.jpg" 6 | export { default as project2 } from "./project2.jpg" 7 | export { default as project3 } from "./project3.jpg" 8 | export { default as project4 } from "./project4.jpg" 9 | export { default as project5 } from "./project5.jpg" 10 | export { default as project6 } from "./project6.jpg" 11 | export { default as profile } from "./profile.png" 12 | export { default as quotes } from "./quotes.svg" -------------------------------------------------------------------------------- /src/Admin/components/SubHeading.jsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | const SubHeading = ({ title }) => { 4 | 5 | ////////////////////////////// VARIABLES ////////////////////////////////////// 6 | 7 | ////////////////////////////// STATES ///////////////////////////////////////// 8 | 9 | ////////////////////////////// USE EFFECTS //////////////////////////////////// 10 | 11 | ////////////////////////////// FUNCTIONS /////////////////////////////////////// 12 | 13 | return ( 14 |
15 |

{title}

16 |
17 | ) 18 | } 19 | 20 | export default SubHeading; -------------------------------------------------------------------------------- /src/assets/quotes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import { BrowserRouter } from "react-router-dom" 6 | import { Provider } from "react-redux" 7 | import { store } from './redux/store' 8 | import { ContextProvider } from "./contexts/ContextProvider" 9 | // import Hover from './utils/Hover/Hover'; 10 | 11 | 12 | ReactDOM.createRoot(document.getElementById('root')).render( 13 | {/* react-redux */} 14 | {/* context-api */} 15 | {/* react-router-dom */} 16 | 17 | {/* */} 18 | 19 | 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /src/utils/pointer.jsx: -------------------------------------------------------------------------------- 1 | import { useState, RefObject, useEffect } from "react"; 2 | 3 | export function useFollowPointer(ref) { 4 | const [point, setPoint] = useState({ x: 0, y: 0 }); 5 | useEffect(() => { 6 | if (!ref.current) return; 7 | 8 | const handlePointerMove = ({ clientX, clientY }) => { 9 | const element = ref.current; 10 | const x = clientX - element.offsetLeft - element.offsetWidth / 2; 11 | const y = clientY - element.offsetTop - element.offsetHeight / 2; 12 | setPoint({ x, y }); 13 | }; 14 | 15 | window.addEventListener("pointermove", handlePointerMove); 16 | 17 | return () => window.removeEventListener("pointermove", handlePointerMove); 18 | }, []); 19 | 20 | return point; 21 | } 22 | -------------------------------------------------------------------------------- /src/redux/actions/contact.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api' 2 | import { start, end, error, getContactUsersReducer, formSubmitReducer, } from '../reducers/contact' 3 | 4 | export const getContactUsers = () => async (dispatch) => { 5 | try { 6 | dispatch(start()) 7 | const { data } = await api.getContactUsers() 8 | dispatch(getContactUsersReducer(data.result)) 9 | dispatch(end()) 10 | } catch (err) { 11 | dispatch(error(err.message)) 12 | } 13 | } 14 | export const formSubmit = () => async (dispatch) => { 15 | try { 16 | dispatch(start()) 17 | const { data } = await api.formSubmit() 18 | dispatch(formSubmitReducer(data.result)) 19 | dispatch(end()) 20 | } catch (err) { 21 | dispatch(error(err.message)) 22 | } 23 | } -------------------------------------------------------------------------------- /src/redux/actions/general.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api' 2 | import { start, end, error, uploadImageReducer, deleteImageReducer } from '../reducers/general' 3 | 4 | export const uploadImage = (formData) => async (dispatch) => { 5 | try { 6 | dispatch(start()) 7 | const { data } = await api.uploadImage(formData) 8 | dispatch(uploadImageReducer(data.result)) 9 | dispatch(end()) 10 | } catch (err) { 11 | dispatch(error(err.message)) 12 | } 13 | } 14 | export const deleteImage = (filename) => async (dispatch) => { 15 | try { 16 | dispatch(start()) 17 | const { data } = await api.deleteImage(filename) 18 | dispatch(deleteImageReducer()) 19 | dispatch(end()) 20 | } catch (err) { 21 | dispatch(error(err.message)) 22 | } 23 | } -------------------------------------------------------------------------------- /src/redux/reducers/general.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const generalSlice = createSlice({ 4 | name: 'general', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | url: null, 9 | }, 10 | reducers: { 11 | start: (state) => { state.isFetching = true, state.error = null }, 12 | end: (state) => { state.isFetching = false, state.error = null }, 13 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 14 | uploadImageReducer: (state, action) => { state.url = action.payload }, 15 | deleteImageReducer: (state) => { state.url = null }, 16 | } 17 | }) 18 | 19 | export const { start, end, error, uploadImageReducer, deleteImageReducer } = generalSlice.actions 20 | export default generalSlice.reducer -------------------------------------------------------------------------------- /src/redux/reducers/contact.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const contactSlice = createSlice({ 4 | name: 'contact', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | contactUsers: [], 9 | }, 10 | reducers: { 11 | start: (state) => { state.isFetching = true, state.error = null }, 12 | end: (state) => { state.isFetching = false, state.error = null }, 13 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 14 | getContactUsersReducer: (state, action) => { state.contactUsers = action.payload }, 15 | formSubmitReducer: (state, action) => { }, 16 | } 17 | }) 18 | 19 | export const { start, end, error, getContactUsersReducer, formSubmitReducer, } = contactSlice.actions 20 | export default contactSlice.reducer -------------------------------------------------------------------------------- /src/User/pages/Resume/ResumeCard.jsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | const ResumeCard = ({ title, subTitle, detail, year }) => { 4 | 5 | return ( 6 |
7 |

{year}

8 |

{title}

9 |

{detail}

10 |
11 |
{subTitle}
12 |
13 |
14 | ) 15 | } 16 | 17 | export default ResumeCard -------------------------------------------------------------------------------- /src/User/pages/Skills/Skillbar.jsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | const Skillbar = ({ skill }) => { 4 | 5 | return ( 6 |
7 |
8 |

{skill.skill}

9 |

{skill.percentage}%

10 |
11 |
12 | 13 |
14 |
15 | ) 16 | } 17 | 18 | export default Skillbar; -------------------------------------------------------------------------------- /src/data/icons.js: -------------------------------------------------------------------------------- 1 | import { Web, Palette, Code, Storage, DesktopMac, WebAsset, Phone, Email, LocationOn, Instagram, FacebookOutlined, Twitter, LinkedIn, GitHub } from '@mui/icons-material'; 2 | 3 | const icons = [ 4 | { icon: Web, name: 'web' }, 5 | { icon: Palette, name: 'palette' }, 6 | { icon: Code, name: 'code' }, 7 | { icon: Storage, name: 'storage' }, 8 | { icon: DesktopMac, name: 'desktopMac' }, 9 | { icon: WebAsset, name: 'webAsset' }, 10 | { icon: Phone, name: 'phone' }, 11 | { icon: Email, name: 'email' }, 12 | { icon: LocationOn, name: 'locationOn' }, 13 | { icon: Instagram, name: 'instagram' }, 14 | { icon: FacebookOutlined, name: 'facebook' }, 15 | { icon: Twitter, name: 'twitter' }, 16 | { icon: LinkedIn, name: 'linkedin' }, 17 | { icon: GitHub, name: 'github' }, 18 | ] 19 | export default icons; -------------------------------------------------------------------------------- /src/User/pages/index.jsx: -------------------------------------------------------------------------------- 1 | // client pages 2 | export { default as Home } from "./Home/Home" 3 | export { default as About } from "./About/About" 4 | export { default as Resume } from "./Resume/Resume" 5 | export { default as Services } from "./Services/Services" 6 | export { default as Skills } from "./Skills/Skills" 7 | export { default as Projects } from "./Projects/Projects" 8 | export { default as Blogs } from "./Blogs/Blogs" 9 | export { default as Freelancing } from "./Freelancing/Freelancing" 10 | export { default as Testimonials } from "./Testimonials/Testimonials" 11 | export { default as Contact } from "./Contact/Contact" 12 | export { default as Footer } from "./Footer/Footer" 13 | // export { default as Login} from "./Auth/Login" 14 | export { default as Login} from "./Auth/Login" 15 | export { default as Register} from "./Auth/Register" 16 | export { default as Account } from "./Account/Account" -------------------------------------------------------------------------------- /src/User/pages/Contact/ContactCard.jsx: -------------------------------------------------------------------------------- 1 | import { icons } from '../../../data' 2 | 3 | const ContactCard = ({ card }) => ( 4 |
5 | 6 | {icons.map((icon, index) => ( 7 | icon.name.toLowerCase() == card.icon.toLowerCase() 8 | && 9 | 10 | ))} 11 | 12 |

{card.title}

13 |

{card.detail}

14 |
15 | ) 16 | 17 | 18 | export default ContactCard; -------------------------------------------------------------------------------- /src/User/pages/Auth/login.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* main login_wrapper */ 4 | .login_wrapper::before { 5 | content: ''; 6 | position: absolute; 7 | top: -50%; 8 | left: -50%; 9 | width: 380px; 10 | height: 420px; 11 | background: linear-gradient(0deg, transparent, #feb931, #feb931); 12 | transform-origin: bottom right; 13 | animation: animate 6s linear infinite; 14 | } 15 | 16 | .login_wrapper::after { 17 | content: ''; 18 | position: absolute; 19 | top: -50%; 20 | left: -50%; 21 | width: 380px; 22 | height: 420px; 23 | background: linear-gradient(0deg, transparent, #feb931, #feb931); 24 | transform-origin: bottom right; 25 | animation: animate 6s linear infinite; 26 | animation-delay: -3s; 27 | } 28 | 29 | @keyframes animate { 30 | 0% { 31 | transform: rotate(0deg); 32 | } 33 | 34 | 100% { 35 | transform: rotate(360deg); 36 | } 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/utils/Loading/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './loading.css' 3 | const Loading = () => { 4 | return ( 5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |

Loading...

21 |
22 | ) 23 | } 24 | 25 | export default Loading -------------------------------------------------------------------------------- /src/contexts/ContextProvider.jsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useState } from "react" 2 | 3 | const StateContext = createContext(); 4 | 5 | export const ContextProvider = ({ children }) => { 6 | 7 | 8 | const [mode, setMode] = useState(localStorage.getItem('mode') || 'user') 9 | const [showSidebar, setShowSidebar] = useState(true) 10 | const [activeNavLink, setActiveNavLink] = useState('overview') 11 | const [windowSize, setWindowSize] = useState({ width: window.innerWidth, height: window.innerHeight }) 12 | 13 | return ( 14 | 24 | {children} 25 | 26 | ) 27 | } 28 | 29 | 30 | 31 | export const useStateContext = () => useContext(StateContext) -------------------------------------------------------------------------------- /src/redux/store.js: -------------------------------------------------------------------------------- 1 | import { combineReducers, configureStore } from '@reduxjs/toolkit' 2 | 3 | import generalReducer from './reducers/general' 4 | import blogReducer from './reducers/blog' 5 | import contactReducer from './reducers/contact' 6 | import freelancingReducer from './reducers/freelancing' 7 | import projectReducer from './reducers/project' 8 | import resumeReducer from './reducers/resume' 9 | import serviceReducer from './reducers/service' 10 | import skillReducer from './reducers/skill' 11 | import testimonialReducer from './reducers/testimonial' 12 | import userReducer from './reducers/user' 13 | 14 | const rootReducer = combineReducers({ 15 | general: generalReducer, 16 | blog: blogReducer, 17 | contact: contactReducer, 18 | freelancing: freelancingReducer, 19 | project: projectReducer, 20 | resume: resumeReducer, 21 | service: serviceReducer, 22 | skill: skillReducer, 23 | testimonial: testimonialReducer, 24 | user: userReducer, 25 | }) 26 | 27 | export const store = configureStore({ 28 | reducer: rootReducer 29 | }) -------------------------------------------------------------------------------- /src/utils/functions.js: -------------------------------------------------------------------------------- 1 | 2 | // 1) 3 | export const limitText = (str, limit) => { 4 | if (str) { 5 | if (str.split("").length > limit) { 6 | const strArr = str.slice(0, limit).trim().split(" ") 7 | const string = strArr.slice(0, strArr.length).join(" ") // strArr.length - 1 8 | return string 9 | } 10 | else { 11 | return str 12 | } 13 | } 14 | } 15 | 16 | 17 | // 2) 18 | export const Capitalize = (str) => { 19 | return str && str.charAt(0).toUpperCase() + str.slice(1); 20 | } 21 | 22 | 23 | // 3) 24 | export const LightenDarkenColor = (col, amt) => { 25 | var num = parseInt(col, 16); 26 | var r = (num >> 16) + amt; 27 | var b = ((num >> 8) & 0x00FF) + amt; 28 | var g = (num & 0x0000FF) + amt; 29 | var newColor = g | (b << 8) | (r << 16); 30 | return newColor.toString(16); 31 | } 32 | 33 | // 4) 34 | export const generateRandom = (from, to) => { 35 | let random = Math.floor(Math.random() * to) + from // random from 1 to 10 36 | return random 37 | } -------------------------------------------------------------------------------- /src/utils/Hover/Hover.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Hover = () => { 4 | 5 | let text = document.querySelectorAll('ul li a').forEach(text => { 6 | text.innerHTML = text.innerText 7 | .split('') 8 | .map((letters, index) => 9 | `${letters}` 10 | ).join('') 11 | }) 12 | 13 | let cursor = document.querySelector('#cursor') 14 | document.addEventListener('mousemove', (e) => { 15 | if (cursor) { 16 | cursor.style.top = e.pageY + 'px' 17 | cursor.style.left = e.pageX + 'px' 18 | } 19 | }) 20 | 21 | 22 | 23 | 24 | return ( 25 | <> 26 |
27 | 35 | 36 | ) 37 | } 38 | 39 | export default Hover -------------------------------------------------------------------------------- /src/redux/reducers/user.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const userSlice = createSlice({ 4 | name: 'user', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | users: [], 9 | currentUser: null, 10 | loggedUser: null 11 | }, 12 | reducers: { 13 | start: (state) => { state.isFetching = true, state.error = null }, 14 | end: (state) => { state.isFetching = false, state.error = null }, 15 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 16 | registerReducer: (state, action) => { state.users = [...state.users, action.payload] }, 17 | loginReducer: (state, action) => { state.loggedUser = action.payload }, 18 | logoutReducer: (state, action) => { state.loggedUser = null }, 19 | getUsersReducer: (state, action) => { state.users = action.payload }, 20 | } 21 | }) 22 | 23 | export const { start, end, error, registerReducer, loginReducer, logoutReducer, getUsersReducer, } = userSlice.actions 24 | export default userSlice.reducer -------------------------------------------------------------------------------- /src/utils/Loading2/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './loading.css' 3 | 4 | const Loading = () => { 5 | return ( 6 |
7 |
8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 | 24 |
25 |
26 | ) 27 | } 28 | 29 | export default Loading -------------------------------------------------------------------------------- /src/User/pages/Services/ServiceCard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Brush, Code, Search } from "@mui/icons-material" 3 | import { icons } from "../../../data" 4 | 5 | 6 | const service = ({ service }) => { 7 | 8 | 9 | return ( 10 |
11 |
12 |
13 | {icons.map((icon, index) => ( 14 | icon.name.toLowerCase() == service.icon.toLowerCase() 15 | && 16 | 17 | ))} 18 |
19 |
20 |

{service.service}

21 | {/*

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Unde, illo.

*/} 22 | {/* Read More */} 23 |
24 |
25 |
26 | 27 | ) 28 | } 29 | 30 | export default service -------------------------------------------------------------------------------- /src/User/components/NavigationDots.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'react-scroll' 2 | 3 | 4 | const NavigationDots = () => { 5 | return ( 6 | <> 7 | { 8 | links.map((item, index) => ( 9 | 20 | {item.title} 21 | 22 | )) 23 | } 24 | 25 | ) 26 | } 27 | 28 | export default NavigationDots 29 | 30 | const links = [ 31 | 'home', 32 | 'about', 33 | 'resume', 34 | 'services', 35 | 'skills', 36 | 'projects', 37 | 'blog', 38 | 'testimonials', 39 | 'contact' 40 | ] -------------------------------------------------------------------------------- /src/User/pages/Testimonials/swiper.css: -------------------------------------------------------------------------------- 1 | /* Swiper bullets */ 2 | 3 | .swiper-pagination-bullets { 4 | position: sticky !important; 5 | bottom: -.4rem !important; 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | height: 3rem; 10 | gap: 6px; 11 | } 12 | 13 | 14 | .swiper-pagination-bullet { 15 | width: 32px !important; 16 | height: 32px !important; 17 | display: flex; 18 | justify-content: center; 19 | align-items: center; 20 | background: black; 21 | color: var(--orange); 22 | font-size: 1.4rem; 23 | font-weight: 600; 24 | border: 2px outset var(--orange); 25 | } 26 | 27 | .swiper-pagination-bullet-active { 28 | display: flex; 29 | justify-content: center; 30 | align-items: center; 31 | background: var(--orange) !important; 32 | color: black; 33 | font-size: 1.4rem; 34 | font-weight: 600; 35 | border: 2px outset black; 36 | } 37 | 38 | .swiper-pagination-bullet:hover { 39 | width: 32px !important; 40 | height: 32px !important; 41 | background: var(--orange); 42 | border: 2px outset black; 43 | color: black; 44 | } -------------------------------------------------------------------------------- /src/redux/reducers/blog.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const blogSlice = createSlice({ 4 | name: 'blog', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | blogs: [], 9 | currentBlog: null 10 | }, 11 | reducers: { 12 | start: (state) => { state.isFetching = true, state.error = null }, 13 | end: (state) => { state.isFetching = false, state.error = null }, 14 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 15 | getBlogsReducer: (state, action) => { state.blogs = action.payload }, 16 | createBlogReducer: (state, action) => { state.blogs = [action.payload, ...state.blogs] }, 17 | updateBlogReducer: (state, action) => { state.blogs = state.blogs.map(b => b = b._id == action.payload._id ? action.payload : b) }, 18 | deleteBlogReducer: (state, action) => { state.blogs = state.blogs.filter(b=>b._id != action.payload._id ) }, 19 | } 20 | }) 21 | 22 | export const { start, end, error, getBlogsReducer, createBlogReducer, updateBlogReducer, deleteBlogReducer, } = blogSlice.actions 23 | export default blogSlice.reducer -------------------------------------------------------------------------------- /src/redux/reducers/skill.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const skillSlice = createSlice({ 4 | name: 'skill', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | skills: [], 9 | currentSkill: null 10 | }, 11 | reducers: { 12 | start: (state) => { state.isFetching = true, state.error = null }, 13 | end: (state) => { state.isFetching = false, state.error = null }, 14 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 15 | getSkillsReducer: (state, action) => { state.skills = action.payload }, 16 | createSkillReducer: (state, action) => { state.skills = [action.payload, ...state.skills] }, 17 | updateSkillReducer: (state, action) => { state.skills = state.skills.map(s => s = s._id == action.payload._id ? action.payload : s) }, 18 | deleteSkillReducer: (state, action) => { state.skills = state.skills.filter(s => s._id != action.payload._id) }, 19 | } 20 | }) 21 | 22 | export const { start, end, error, getSkillsReducer, createSkillReducer, updateSkillReducer, deleteSkillReducer, } = skillSlice.actions 23 | export default skillSlice.reducer -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: { 6 | colors: { 7 | 'orange': '#feb931', 8 | 'gray': '#9f9e9d', 9 | 'white': '#fff', 10 | 'linkBlue': '#71a5ea', 11 | 'textGray': '#797979', 12 | 'darkGray': '#1a1a1a', 13 | 'lightGray': '#222222', 14 | 'red': '#ff0000', 15 | }, 16 | backgroundColor: { 17 | 'gray-background': '#191919', 18 | 'black': '#000', 19 | }, 20 | backgroundImage: { 21 | 'parallax-image': "url('/assets/bg_1.png')", 22 | }, 23 | animation: { 24 | slideup: 'slideup 1s ease-in-out', 25 | }, 26 | keyframes: { 27 | slideup: { 28 | from: { opacity: 0, transform: 'translateY(25%)' }, 29 | to: { opacity: 1, transform: 'none' }, 30 | }, 31 | wave: { 32 | '0%': { transform: 'scale(0)' }, 33 | '50%': { transform: 'scale(1)' }, 34 | '100%': { transform: 'scale(0)' }, 35 | }, 36 | }, 37 | }, 38 | }, 39 | variants: {}, 40 | plugins: [], 41 | }; -------------------------------------------------------------------------------- /src/redux/reducers/freelancing.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const freelancingSlice = createSlice({ 4 | name: 'freelancing', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | cards: [], 9 | currentFreelancing: null 10 | }, 11 | reducers: { 12 | start: (state) => { state.isFetching = true, state.error = null }, 13 | end: (state) => { state.isFetching = false, state.error = null }, 14 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 15 | getCardsReducer: (state, action) => { state.cards = action.payload }, 16 | createCardReducer: (state, action) => { state.cards = [action.payload, ...state.cards] }, 17 | updateCardReducer: (state, action) => { state.cards = state.cards.map(c => c = c._id == action.payload._id ? action.payload : c) }, 18 | deleteCardReducer: (state, action) => { state.cards = state.cards.filter(c => c._id != action.payload._id) }, 19 | } 20 | }) 21 | 22 | export const { start, end, error, getCardsReducer, createCardReducer, updateCardReducer, deleteCardReducer, } = freelancingSlice.actions 23 | export default freelancingSlice.reducer -------------------------------------------------------------------------------- /src/redux/reducers/resume.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const resumeSlice = createSlice({ 4 | name: 'resume', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | resumes: [], 9 | currentResume: null 10 | }, 11 | reducers: { 12 | start: (state) => { state.isFetching = true, state.error = null }, 13 | end: (state) => { state.isFetching = false, state.error = null }, 14 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 15 | getResumesReducer: (state, action) => { state.resumes = action.payload }, 16 | createResumeReducer: (state, action) => { state.resumes = [action.payload, ...state.resumes] }, 17 | updateResumeReducer: (state, action) => { state.resumes = state.resumes.map(r => r = r._id == action.payload._id ? action.payload : r) }, 18 | deleteResumeReducer: (state, action) => { state.resumes = state.resumes.filter(r => r._id != action.payload._id) }, 19 | } 20 | }) 21 | 22 | export const { start, end, error, getResumesReducer, createResumeReducer, updateResumeReducer, deleteResumeReducer, } = resumeSlice.actions 23 | export default resumeSlice.reducer -------------------------------------------------------------------------------- /src/redux/reducers/service.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const serviceSlice = createSlice({ 4 | name: 'service', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | services: [], 9 | currentService: null 10 | }, 11 | reducers: { 12 | start: (state) => { state.isFetching = true, state.error = null }, 13 | end: (state) => { state.isFetching = false, state.error = null }, 14 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 15 | getServicesReducer: (state, action) => { state.services = action.payload }, 16 | createServiceReducer: (state, action) => { state.services = [action.payload, ...state.services] }, 17 | updateServiceReducer: (state, action) => { state.services = state.services.map(s => s = s._id == action.payload._id ? action.payload : s) }, 18 | deleteServiceReducer: (state, action) => { state.services = state.services.filter(s => s._id != action.payload._id) }, 19 | } 20 | }) 21 | 22 | export const { start, end, error, getServicesReducer, createServiceReducer, updateServiceReducer, deleteServiceReducer, } = serviceSlice.actions 23 | export default serviceSlice.reducer -------------------------------------------------------------------------------- /src/User/pages/Testimonials/TestimonialsCard.jsx: -------------------------------------------------------------------------------- 1 | import { FormatQuote } from "@mui/icons-material" 2 | 3 | const TestimonialsCard = ({ content, name, designation, image }) => { 4 | return ( 5 |
6 | 7 | 8 | 9 |

10 | {content} 11 |

12 | 13 |
14 | {name} 15 |
16 |

{name}

17 |

{designation}

18 |
19 |
20 |
21 | ) 22 | } 23 | 24 | export default TestimonialsCard 25 | -------------------------------------------------------------------------------- /src/redux/reducers/project.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const projectSlice = createSlice({ 4 | name: 'project', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | projects: [], 9 | currentProject: null 10 | }, 11 | reducers: { 12 | start: (state) => { state.isFetching = true, state.error = null }, 13 | end: (state) => { state.isFetching = false, state.error = null }, 14 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 15 | getProjectsReducer: (state, action) => { state.projects = action.payload }, 16 | createProjectReducer: (state, action) => { state.projects = [action.payload, ...state.projects] }, 17 | updateProjectReducer: (state, action) => { state.projects = state.projects.map(p => p = p._id == action.payload._id ? action.payload : p) }, 18 | deleteProjectReducer: (state, action) => { state.projects = state.projects.filter(p => p._id != action.payload._id) }, 19 | } 20 | }) 21 | 22 | export const { start, end, error, getProjectsReducer, createProjectReducer, uploadProjectImageReducer, updateProjectReducer, deleteProjectReducer, } = projectSlice.actions 23 | export default projectSlice.reducer -------------------------------------------------------------------------------- /src/redux/reducers/testimonial.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const testimonialSlice = createSlice({ 4 | name: 'testimonial', 5 | initialState: { 6 | isFetching: false, 7 | error: null, 8 | testimonials: [], 9 | currentTestimonial: null 10 | }, 11 | reducers: { 12 | start: (state) => { state.isFetching = true, state.error = null }, 13 | end: (state) => { state.isFetching = false, state.error = null }, 14 | error: (state, action) => { state.isFetching = false, state.error = action.payload }, 15 | getTestimonialsReducer: (state, action) => { state.testimonials = action.payload }, 16 | createTestimonialReducer: (state, action) => { state.testimonials = [action.payload, ...state.testimonials] }, 17 | updateTestimonialReducer: (state, action) => { state.testimonials = state.testimonials.map(t => t = t._id == action.payload._id ? action.payload : t) }, 18 | deleteTestimonialReducer: (state, action) => { state.testimonials = state.testimonials.filter(t => t._id != action.payload._id) }, 19 | } 20 | }) 21 | 22 | export const { start, end, error, getTestimonialsReducer, createTestimonialReducer, updateTestimonialReducer, deleteTestimonialReducer, } = testimonialSlice.actions 23 | export default testimonialSlice.reducer -------------------------------------------------------------------------------- /src/Admin/components/Heading.jsx: -------------------------------------------------------------------------------- 1 | import { Add, MoreVert } from '@mui/icons-material' 2 | import { useState } from 'react' 3 | 4 | const Heading = ({ title, setOpen }) => { 5 | 6 | ////////////////////////////// VARIABLES ////////////////////////////////////// 7 | 8 | ////////////////////////////// STATES ///////////////////////////////////////// 9 | const [showMenu, setShowMenu] = useState(false) 10 | ////////////////////////////// USE EFFECTS //////////////////////////////////// 11 | 12 | ////////////////////////////// FUNCTIONS /////////////////////////////////////// 13 | 14 | 15 | 16 | return ( 17 |
18 |
19 |

{title}

20 |
21 |
22 | { 23 | setOpen 24 | ? 25 |
26 | 27 |
28 | : 29 | '' 30 | } 31 |
32 | ) 33 | } 34 | 35 | export default Heading; -------------------------------------------------------------------------------- /src/utils/Hover/hover.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | /* body { 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | min-height: 100vh; 12 | background: #222; 13 | cursor: none; 14 | } */ 15 | 16 | ul { 17 | position: relative; 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | flex-direction: column; 22 | } 23 | 24 | ul li { 25 | position: relative; 26 | padding: 10px 0; 27 | text-align: center; 28 | list-style: none; 29 | } 30 | 31 | ul li a { 32 | text-decoration: none; 33 | color: #555; 34 | cursor: none; 35 | } 36 | 37 | ul li a span { 38 | position: relative; 39 | font-size: 2.5em; 40 | letter-spacing: 0.05em; 41 | transition: 0.25s; 42 | text-transform: uppercase; 43 | } 44 | 45 | ul li:hover a span { 46 | color: #fff; 47 | text-shadow: 0 0 5px #fff, 48 | 0 0 15px #fff, 49 | 0 0 30px #fff, 50 | 0 0 60px #fff, 51 | 0 0 100px #fff; 52 | } 53 | 54 | #cursor { 55 | position: fixed; 56 | width: 20px; 57 | height: 20px; 58 | border-radius: 50%; 59 | background: #fff; 60 | box-shadow: 0 0 5px #fff, 61 | 0 0 15px #fff, 62 | 0 0 30px #fff, 63 | 0 0 60px #fff; 64 | transform: translate(-50%, -50%); 65 | pointer-events: none; 66 | opacity: 0; 67 | } 68 | 69 | /* body:hover #cursor { 70 | opacity: 1; 71 | } */ -------------------------------------------------------------------------------- /src/utils/Cursor/cursor.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | 8 | 9 | /* body { 10 | min-height: 100vh; 11 | overflow: hidden; 12 | background: #222; 13 | background-image: 14 | linear-gradient(to right, #333 1px, transparent 1px), 15 | linear-gradient(to bottom, #333 1px, transparent 1px); 16 | background-size: 40px 40px; 17 | cursor: none; 18 | } */ 19 | 20 | #cursor { 21 | position: fixed; 22 | width: 25px; 23 | height: 25px; 24 | border-top: 5px solid #0f0; 25 | border-left: 5px solid #0f0; 26 | transform-origin: top; 27 | transform: translate(-1px, 5px) rotate(15deg); 28 | transition: transform 0.5s; 29 | pointer-events: none; 30 | filter: drop-shadow(0 0 5px #0f0) drop-shadow(0 0 15px #0f0) drop-shadow(0 0 35px #0f0) hue-rotate(60deg); 31 | } 32 | 33 | #cursor::before { 34 | content: ''; 35 | position: absolute; 36 | left: -2.5px; 37 | width: 5px; 38 | height: 40px; 39 | background: #0f0; 40 | transform-origin: top; 41 | transform: rotate(315deg); 42 | 43 | } 44 | 45 | body:hover #cursor { 46 | transform: translate(-1px, 5px) rotate(15deg) scale(1); 47 | } 48 | 49 | 50 | .element { 51 | position: absolute; 52 | transform: translate(-50%, -50%); 53 | color: #0f0; 54 | pointer-events: none; 55 | width: 10px; 56 | height: 10px; 57 | font-size: 2em; 58 | transition: 1s; 59 | filter: drop-shadow(0 0 5px #0f0) drop-shadow(0 0 25px #0f0) hue-rotate(60deg); 60 | } -------------------------------------------------------------------------------- /src/User/pages/Account/Account.jsx: -------------------------------------------------------------------------------- 1 | import { CircularProgress } from '@mui/material' 2 | import { useDispatch, useSelector } from 'react-redux' 3 | import { useNavigate } from 'react-router-dom' 4 | import { Button } from "../../components" 5 | import { logout } from '../../../redux/actions/user' 6 | 7 | 8 | const Account = () => { 9 | const { loggedUser, isFetching, error } = useSelector(state => state.user) 10 | 11 | //////////////////////////////////////////////////// Variables /////////////////////////////////////////////////////// 12 | const navigate = useNavigate() 13 | const dispatch = useDispatch() 14 | 15 | //////////////////////////////////////////////////// States /////////////////////////////////////////////////////// 16 | 17 | //////////////////////////////////////////////////// useEffect /////////////////////////////////////////////////////// 18 | 19 | //////////////////////////////////////////////////// Functions /////////////////////////////////////////////////////// 20 | const logoutFunc = () => { 21 | dispatch(logout(navigate)) 22 | } 23 | 24 | return ( 25 | <> 26 | { 27 | isFetching 28 | ? 29 | 30 | : 31 | 33 | 36 | 37 | 38 | ); 39 | } 40 | 41 | export default Confirm -------------------------------------------------------------------------------- /src/redux/actions/freelancing.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api' 2 | import { start, end, error, getCardsReducer, createCardReducer, updateCardReducer, deleteCardReducer, } from '../reducers/freelancing' 3 | 4 | 5 | export const getCards = () => async (dispatch) => { 6 | try { 7 | dispatch(start()) 8 | const { data } = await api.getCards() 9 | dispatch(getCardsReducer(data.result)) 10 | dispatch(end()) 11 | } catch (err) { 12 | dispatch(error(err.message)) 13 | } 14 | } 15 | export const createCard = (cardData, setOpen) => async (dispatch) => { 16 | try { 17 | dispatch(start()) 18 | const { data } = await api.createCard(cardData) 19 | dispatch(createCardReducer(data.result)) 20 | dispatch(end()) 21 | setOpen(false) 22 | } catch (err) { 23 | dispatch(error(err.message)) 24 | } 25 | } 26 | export const updateCard = (cardId,cardData, setOpen) => async (dispatch) => { 27 | try { 28 | dispatch(start()) 29 | const { data } = await api.updateCard(cardId, cardData) 30 | dispatch(updateCardReducer(data.result)) 31 | dispatch(end()) 32 | setOpen(false) 33 | } catch (err) { 34 | dispatch(error(err.message)) 35 | } 36 | } 37 | export const deleteCard = (cardId, setOpen) => async (dispatch) => { 38 | try { 39 | dispatch(start()) 40 | const { data } = await api.deleteCard(cardId) 41 | dispatch(deleteCardReducer(data.result)) 42 | dispatch(end()) 43 | setOpen(false) 44 | } catch (err) { 45 | dispatch(error(err.message)) 46 | } 47 | } -------------------------------------------------------------------------------- /src/redux/actions/skill.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api' 2 | import { start, end, error, getSkillsReducer, createSkillReducer, updateSkillReducer, deleteSkillReducer, } from '../reducers/skill' 3 | 4 | 5 | export const getSkills = () => async (dispatch) => { 6 | try { 7 | dispatch(start()) 8 | const { data } = await api.getSkills() 9 | dispatch(getSkillsReducer(data.result)) 10 | dispatch(end()) 11 | } catch (err) { 12 | dispatch(error(err.message)) 13 | } 14 | } 15 | export const createSkill = (skillData, setOpen) => async (dispatch) => { 16 | try { 17 | dispatch(start()) 18 | const { data } = await api.createSkill(skillData) 19 | dispatch(createSkillReducer(data.result)) 20 | dispatch(end()) 21 | setOpen(false) 22 | } catch (err) { 23 | dispatch(error(err.message)) 24 | } 25 | } 26 | export const updateSkill = (skillId, skillData, setOpen) => async (dispatch) => { 27 | try { 28 | dispatch(start()) 29 | const { data } = await api.updateSkill(skillId, skillData) 30 | dispatch(updateSkillReducer(data.result)) 31 | dispatch(end()) 32 | setOpen(false) 33 | } catch (err) { 34 | dispatch(error(err.message)) 35 | } 36 | } 37 | export const deleteSkill = (skillId,setOpen) => async (dispatch) => { 38 | try { 39 | dispatch(start()) 40 | const { data } = await api.deleteSkill(skillId) 41 | dispatch(deleteSkillReducer(data.result)) 42 | dispatch(end()) 43 | setOpen(false) 44 | } catch (err) { 45 | dispatch(error(err.message)) 46 | } 47 | } -------------------------------------------------------------------------------- /src/redux/actions/resume.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api' 2 | import { start, end, error, getResumesReducer, createResumeReducer, updateResumeReducer, deleteResumeReducer, } from '../reducers/resume' 3 | 4 | 5 | export const getResumes = () => async (dispatch) => { 6 | try { 7 | dispatch(start()) 8 | const { data } = await api.getResumes() 9 | dispatch(getResumesReducer(data.result)) 10 | dispatch(end()) 11 | } catch (err) { 12 | dispatch(error(err.message)) 13 | } 14 | } 15 | export const createResume = (resumeData, setOpen) => async (dispatch) => { 16 | try { 17 | dispatch(start()) 18 | const { data } = await api.createResume(resumeData) 19 | dispatch(createResumeReducer(data.result)) 20 | dispatch(end()) 21 | setOpen(false) 22 | } catch (err) { 23 | dispatch(error(err.message)) 24 | } 25 | } 26 | export const updateResume = (resumeId, resumeData, setOpen) => async (dispatch) => { 27 | try { 28 | dispatch(start()) 29 | const { data } = await api.updateResume(resumeId, resumeData) 30 | dispatch(updateResumeReducer(data.result)) 31 | dispatch(end()) 32 | setOpen(false) 33 | } catch (err) { 34 | dispatch(error(err.message)) 35 | } 36 | } 37 | export const deleteResume = (resumeId, setOpen) => async (dispatch) => { 38 | try { 39 | dispatch(start()) 40 | const { data } = await api.deleteResume(resumeId) 41 | dispatch(deleteResumeReducer(data.result)) 42 | dispatch(end()) 43 | setOpen(false) 44 | } catch (err) { 45 | dispatch(error(err.message)) 46 | } 47 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Full Stack Developer Portfolio Website 2 | 3 | This project, built using MERN and Framer Motion, is a full stack portfolio application with complete management of website content through associated admin panel. 4 | 5 | ### Main Sections 6 | 7 | - Header 8 | - About 9 | - Services 10 | - Skills 11 | - Projects 12 | - Testimonials 13 | - Freelancing 14 | - Contact 15 | - Get Notified 16 | 17 | ### Admin Panel 18 | 19 | With the admin panel, admin gain complete control over the website to manage projects, services, testimonials, contact users, website content, and more—all from one convenient dashboard. 20 | 21 | ## Tech Stack 22 | 23 | - Frontend: React, Framer Motion, Tailwind CSS, Material UI 24 | - Backend: MERN Stack (MongoDB, Express.js, React.js, Node.js) 25 | 26 | ## Getting Started 27 | 28 | 1. Clone the repository: 29 | 30 | ```bash 31 | git clone https://github.com/naumanch969/fullstack-portfolio.git 32 | ``` 33 | 34 | 2. Install dependencies: 35 | 36 | ```bash 37 | cd your-portfolio 38 | npm install 39 | ``` 40 | 41 | 3. Start the development server: 42 | 43 | ```bash 44 | npm start 45 | ``` 46 | 47 | 4. Open your browser and visit `http://localhost:3000` to view the website locally. 48 | 49 | ## Contributing 50 | 51 | Contributions are welcome! If you have any suggestions, enhancements, or bug fixes, feel free to open an issue or submit a pull request. 52 | 53 | ## Contact 54 | 55 | Have questions or feedback? Feel free to reach out to me: 56 | 57 | - Email: naumanch969@gmail.com 58 | - LinkedIn: [My LinkedIn Profile](https://www.linkedin.com/in/naumanch/) 59 | 60 | Thank you for visiting my repository and exploring my portfolio website! 😊🚀 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elagant-music-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@emotion/react": "^11.10.4", 12 | "@emotion/styled": "^11.10.4", 13 | "@mui/icons-material": "^5.10.9", 14 | "@mui/material": "^5.10.10", 15 | "@mui/x-data-grid": "^6.11.1", 16 | "@reduxjs/toolkit": "^1.9.5", 17 | "axios": "^0.27.2", 18 | "elagant-music-app": "file:", 19 | "email-validator": "^2.0.4", 20 | "framer-motion": "^7.6.1", 21 | "js-cookie": "^3.0.1", 22 | "react": "^18.2.0", 23 | "react-date-picker": "^9.2.0", 24 | "react-datetime": "^3.2.0", 25 | "react-dom": "^18.2.0", 26 | "react-file-base64": "^1.0.3", 27 | "react-icons": "^4.4.0", 28 | "react-phone-number-input": "^3.2.19", 29 | "react-redux": "^8.1.2", 30 | "react-router-dom": "^6.3.0", 31 | "react-scroll": "^1.8.7", 32 | "react-textarea-autosize": "^8.4.0", 33 | "redux": "^4.2.1", 34 | "redux-thunk": "^2.4.2", 35 | "swiper": "^8.4.7" 36 | }, 37 | "devDependencies": { 38 | "@types/react": "^18.0.0", 39 | "@types/react-dom": "^18.0.0", 40 | "@vitejs/plugin-react": "^1.3.0", 41 | "autoprefixer": "^10.4.7", 42 | "eslint": "^8.18.0", 43 | "eslint-config-airbnb": "^19.0.4", 44 | "eslint-plugin-import": "^2.26.0", 45 | "eslint-plugin-jsx-a11y": "^6.5.1", 46 | "eslint-plugin-react": "^7.30.0", 47 | "eslint-plugin-react-hooks": "^4.6.0", 48 | "postcss": "^8.4.14", 49 | "tailwindcss": "^3.1.3", 50 | "vite": "^2.9.9" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/redux/actions/service.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api' 2 | import { start, end, error, getServicesReducer, createServiceReducer, updateServiceReducer, deleteServiceReducer, } from '../reducers/service' 3 | 4 | 5 | export const getServices = () => async (dispatch) => { 6 | try { 7 | dispatch(start()) 8 | const { data } = await api.getServices() 9 | dispatch(getServicesReducer(data.result)) 10 | dispatch(end()) 11 | } catch (err) { 12 | dispatch(error(err.message)) 13 | } 14 | } 15 | export const createService = (serviceData, setOpen) => async (dispatch) => { 16 | try { 17 | dispatch(start()) 18 | const { data } = await api.createService(serviceData) 19 | dispatch(createServiceReducer(data.result)) 20 | dispatch(end()) 21 | setOpen(false) 22 | } catch (err) { 23 | dispatch(error(err.message)) 24 | } 25 | } 26 | export const updateService = (serviceId, serviceData, setOpen) => async (dispatch) => { 27 | try { 28 | dispatch(start()) 29 | const { data } = await api.updateService(serviceId, serviceData) 30 | dispatch(updateServiceReducer(data.result)) 31 | dispatch(end()) 32 | setOpen(false) 33 | } catch (err) { 34 | dispatch(error(err.message)) 35 | } 36 | } 37 | export const deleteService = (serviceId, setOpen) => async (dispatch) => { 38 | try { 39 | dispatch(start()) 40 | const { data } = await api.deleteService(serviceId) 41 | dispatch(deleteServiceReducer(data.result)) 42 | dispatch(end()) 43 | setOpen(false) 44 | } catch (err) { 45 | dispatch(error(err.message)) 46 | } 47 | } -------------------------------------------------------------------------------- /src/Admin/pages/Blogs/Delete.jsx: -------------------------------------------------------------------------------- 1 | import { Dialog, DialogTitle, DialogContent, DialogActions, Button, DialogContentText } from '@mui/material' 2 | import React from 'react' 3 | import { useDispatch, useSelector } from 'react-redux' 4 | import { deleteBlog } from '../../../redux/actions/blog' 5 | 6 | const DeleteModal = ({ open, setOpen, blogId }) => { 7 | 8 | ////////////////////////////////////// VARIABLES /////////////////////////////////////// 9 | const dispatch = useDispatch() 10 | const { isFetching } = useSelector(state => state.blog) 11 | 12 | ////////////////////////////////////// FUNCTIONS /////////////////////////////////////// 13 | const handleClose = () => { 14 | setOpen(false) 15 | } 16 | const handleDelete = () => { 17 | dispatch(deleteBlog(blogId, setOpen)) 18 | setOpen(false) 19 | } 20 | 21 | return ( 22 | setOpen(false)} 25 | > 26 | 27 | Delete the Blog? 28 | 29 | 30 | 31 | Are you sure you want to delete this blog? 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default DeleteModal -------------------------------------------------------------------------------- /src/Admin/pages/Skills/Delete.jsx: -------------------------------------------------------------------------------- 1 | import { Dialog, DialogTitle, DialogContent, DialogActions, Button, DialogContentText } from '@mui/material' 2 | import React from 'react' 3 | import { useDispatch, useSelector } from 'react-redux' 4 | import { deleteSkill } from '../../../redux/actions/skill' 5 | 6 | const DeleteModal = ({ open, setOpen, skillId }) => { 7 | 8 | ////////////////////////////////////// VARIABLES /////////////////////////////////////// 9 | const dispatch = useDispatch() 10 | const { isFetching } = useSelector(state => state.skill) 11 | 12 | ////////////////////////////////////// FUNCTIONS /////////////////////////////////////// 13 | const handleClose = () => { 14 | setOpen(false) 15 | } 16 | const handleDelete = () => { 17 | dispatch(deleteSkill(skillId, setOpen)) 18 | setOpen(false) 19 | } 20 | 21 | return ( 22 | setOpen(false)} 25 | > 26 | 27 | Delete the Skill? 28 | 29 | 30 | 31 | Are you sure you want to delete this skill? 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default DeleteModal -------------------------------------------------------------------------------- /src/Admin/pages/Freelancing/Delete.jsx: -------------------------------------------------------------------------------- 1 | import { Dialog, DialogTitle, DialogContent, DialogActions, Button, DialogContentText } from '@mui/material' 2 | import React from 'react' 3 | import { useDispatch, useSelector } from 'react-redux' 4 | import { deleteCard } from '../../../redux/actions/freelancing' 5 | 6 | const DeleteModal = ({ open, setOpen, cardId }) => { 7 | 8 | ////////////////////////////////////// VARIABLES /////////////////////////////////////// 9 | const dispatch = useDispatch() 10 | const { isFetching } = useSelector(state => state.freelancing) 11 | 12 | ////////////////////////////////////// FUNCTIONS /////////////////////////////////////// 13 | const handleClose = () => { 14 | setOpen(false) 15 | } 16 | const handleDelete = () => { 17 | dispatch(deleteCard(cardId, setOpen)) 18 | setOpen(false) 19 | } 20 | 21 | return ( 22 | setOpen(false)} 25 | > 26 | 27 | Delete the Card? 28 | 29 | 30 | 31 | Are you sure you want to delete this card? 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default DeleteModal -------------------------------------------------------------------------------- /src/Admin/pages/Resumes/Delete.jsx: -------------------------------------------------------------------------------- 1 | import { Dialog, DialogTitle, DialogContent, DialogActions, Button, DialogContentText } from '@mui/material' 2 | import React from 'react' 3 | import { useDispatch, useSelector } from 'react-redux' 4 | import { deleteResume } from '../../../redux/actions/resume' 5 | 6 | const DeleteModal = ({ open, setOpen, resumeId }) => { 7 | 8 | ////////////////////////////////////// VARIABLES /////////////////////////////////////// 9 | const dispatch = useDispatch() 10 | const { isFetching } = useSelector(state => state.resume) 11 | 12 | ////////////////////////////////////// FUNCTIONS /////////////////////////////////////// 13 | const handleClose = () => { 14 | setOpen(false) 15 | } 16 | const handleDelete = () => { 17 | dispatch(deleteResume(resumeId, setOpen)) 18 | setOpen(false) 19 | } 20 | 21 | return ( 22 | setOpen(false)} 25 | > 26 | 27 | Delete the Resume? 28 | 29 | 30 | 31 | Are you sure you want to delete this resume? 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default DeleteModal -------------------------------------------------------------------------------- /src/redux/actions/project.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api' 2 | import { start, end, error, getProjectsReducer, createProjectReducer, uploadProjectImageReducer, updateProjectReducer, deleteProjectReducer, } from '../reducers/project' 3 | 4 | 5 | export const getProjects = () => async (dispatch) => { 6 | try { 7 | dispatch(start()) 8 | const { data } = await api.getProjects() 9 | dispatch(getProjectsReducer(data.result)) 10 | dispatch(end()) 11 | } catch (err) { 12 | dispatch(error(err.message)) 13 | } 14 | } 15 | export const createProject = (projectData, setOpen) => async (dispatch) => { 16 | try { 17 | dispatch(start()) 18 | const { data } = await api.createProject(projectData) 19 | dispatch(createProjectReducer(data.result)) 20 | dispatch(end()) 21 | setOpen(false) 22 | } catch (err) { 23 | dispatch(error(err.message)) 24 | } 25 | } 26 | export const updateProject = (projectId, projectData, setOpen) => async (dispatch) => { 27 | try { 28 | dispatch(start()) 29 | const { data } = await api.updateProject(projectId, projectData) 30 | dispatch(updateProjectReducer(data.result)) 31 | dispatch(end()) 32 | setOpen(false) 33 | } catch (err) { 34 | dispatch(error(err.message)) 35 | } 36 | } 37 | export const deleteProject = (projectId, setOpen) => async (dispatch) => { 38 | try { 39 | dispatch(start()) 40 | const { data } = await api.deleteProject(projectId) 41 | dispatch(deleteProjectReducer(data.result)) 42 | dispatch(end()) 43 | setOpen(false) 44 | } catch (err) { 45 | dispatch(error(err.message)) 46 | } 47 | } -------------------------------------------------------------------------------- /src/utils/Input/Input.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { VisibilityOff, RemoveRedEye } from '@mui/icons-material' 3 | 4 | const Input = ({ type, placeholder, attribute, blurFunction, showEyeIcon, formData, setFormData, textarea, rows }) => { // attribute may either of 'email', 'name', 'password', 'confirmPassword' 5 | 6 | const [showPassword, setShowPassword] = useState(false) 7 | 8 | const handleChange = (e) => { 9 | setFormData({ ...formData, [attribute]: e.target.value }) 10 | } 11 | 12 | const attributes = { 13 | autoComplete: 'off', 14 | type: showPassword ? 'text' : type, 15 | placeholder: placeholder, 16 | name: attribute, 17 | value: formData[attribute], 18 | onChange: handleChange, 19 | onBlur: blurFunction, 20 | className: 'bg-inherit w-full text-textGray border-b-[1px] border-textGray p-[6px] outline-none pl-0', 21 | required: true 22 | } 23 | 24 | return ( 25 |
26 | 27 |
28 | { 29 | textarea 30 | ? 31 |