├── .eslintrc.json ├── .DS_Store ├── public ├── .DS_Store ├── images │ ├── .DS_Store │ ├── 1ds.jpg │ ├── favicon.png │ ├── profile.png │ ├── guess-game.png │ ├── snake-game.png │ ├── landing-page.png │ ├── movie-magnet.png │ ├── old-favicon.png │ ├── weather-app.png │ ├── delta-assistant.png │ ├── react-notes-app.png │ ├── dice-multiplayer.png │ ├── portfolio-website.png │ ├── text-utility-app.png │ ├── ar-profile-transformed.png │ └── fmr.svg └── files │ └── vaheed_cv.pdf ├── .vscode └── settings.json ├── .gitignore ├── next.config.js ├── .env.sample ├── src ├── middleware.js ├── app │ ├── sitemap.xml.js │ ├── experience │ │ ├── page.jsx │ │ └── WorkCard.jsx │ ├── about │ │ ├── InterestsCard.jsx │ │ └── page.jsx │ ├── contact │ │ ├── MapBox.jsx │ │ ├── page.jsx │ │ └── ContactForm.jsx │ ├── blogs │ │ ├── ArticlesCard.jsx │ │ ├── NewsLetterComponent.jsx │ │ └── page.jsx │ ├── projects │ │ ├── ProjectCard.jsx │ │ └── page.jsx │ ├── layout.jsx │ ├── page.jsx │ └── skills │ │ └── page.jsx ├── components │ ├── RadioCards.jsx │ ├── DrawerComponent.jsx │ ├── ClientRootLayout.jsx │ ├── SocialIcons.jsx │ ├── MobileHeader.jsx │ ├── Providers.jsx │ └── Header.jsx ├── utils │ ├── utils.js │ └── constants.js ├── particlesjs.json └── styles │ └── main.scss ├── package.json └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/.DS_Store -------------------------------------------------------------------------------- /public/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/.DS_Store -------------------------------------------------------------------------------- /public/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/.DS_Store -------------------------------------------------------------------------------- /public/images/1ds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/1ds.jpg -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/favicon.png -------------------------------------------------------------------------------- /public/images/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/profile.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Chakra", 4 | "MAPBOX" 5 | ] 6 | } -------------------------------------------------------------------------------- /public/files/vaheed_cv.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/files/vaheed_cv.pdf -------------------------------------------------------------------------------- /public/images/guess-game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/guess-game.png -------------------------------------------------------------------------------- /public/images/snake-game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/snake-game.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .next 3 | .vscode 4 | .env 5 | .env.production 6 | .env.staging 7 | .env.development -------------------------------------------------------------------------------- /public/images/landing-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/landing-page.png -------------------------------------------------------------------------------- /public/images/movie-magnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/movie-magnet.png -------------------------------------------------------------------------------- /public/images/old-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/old-favicon.png -------------------------------------------------------------------------------- /public/images/weather-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/weather-app.png -------------------------------------------------------------------------------- /public/images/delta-assistant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/delta-assistant.png -------------------------------------------------------------------------------- /public/images/react-notes-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/react-notes-app.png -------------------------------------------------------------------------------- /public/images/dice-multiplayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/dice-multiplayer.png -------------------------------------------------------------------------------- /public/images/portfolio-website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/portfolio-website.png -------------------------------------------------------------------------------- /public/images/text-utility-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/text-utility-app.png -------------------------------------------------------------------------------- /public/images/ar-profile-transformed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/worker/portfolio/main/public/images/ar-profile-transformed.png -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | sassOptions: { 5 | includePaths: [path.join(__dirname, "src", "styles")], 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_GOOGLE_ANALYTICS= 2 | NEXT_PUBLIC_MAPBOX_TOKEN= 3 | NEXT_PUBLIC_HASHNODE_API=https://api.hashnode.com/ 4 | NEXT_PUBLIC_HASHNODE_API_TOKEN= 5 | NEXT_PUBLIC_HASHNODE_PUBLICATION_ID= 6 | NEXT_PUBLIC_FAB_FORM_KEY= -------------------------------------------------------------------------------- /src/middleware.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export function middleware(request) { 4 | if (request.nextUrl.pathname.startsWith('/newsletter')) { 5 | return NextResponse.rewrite("https://codersk36.hashnode.dev/api/newsletter/subscribe") 6 | } 7 | } -------------------------------------------------------------------------------- /src/app/sitemap.xml.js: -------------------------------------------------------------------------------- 1 | export async function GET() { 2 | const baseUrl = 'https://vaheedshaik.com'; 3 | const staticPages = [ 4 | '', // home 5 | 'about', 6 | 'projects', 7 | 'blogs', 8 | 'contact', 9 | 'skills', 10 | 'certifications', 11 | 'experience', 12 | ]; 13 | 14 | const urls = staticPages.map( 15 | (page) => ` \n ${baseUrl}/${page}\n monthly\n 0.8\n ` 16 | ).join('\n'); 17 | 18 | const sitemap = `\n\n${urls}\n`; 19 | 20 | return new Response(sitemap, { 21 | headers: { 22 | 'Content-Type': 'application/xml', 23 | }, 24 | }); 25 | } -------------------------------------------------------------------------------- /src/components/RadioCards.jsx: -------------------------------------------------------------------------------- 1 | import { Box, useRadio } from "@chakra-ui/react"; 2 | 3 | const RadioCard = (props) => { 4 | const { getInputProps, getRadioProps } = useRadio(props); 5 | 6 | const input = getInputProps(); 7 | const checkbox = getRadioProps(); 8 | 9 | return ( 10 | 11 | 12 | 29 | {props.children} 30 | 31 | 32 | ); 33 | }; 34 | 35 | export default RadioCard; 36 | -------------------------------------------------------------------------------- /src/app/experience/page.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import WorkCard from "./WorkCard"; 4 | import { Heading, SimpleGrid, Center, Box } from "@chakra-ui/react"; 5 | import { workData } from "../../utils/constants"; 6 | import { RevealWrapper } from "next-reveal"; 7 | 8 | const Work = () => { 9 | return ( 10 | <> 11 |
12 | 13 | 14 | EXPERIENCE 15 | 16 | 17 | 18 | {workData.map((data, index) => { 19 | return ; 20 | })} 21 | 22 | 23 | 24 |
25 | 26 | ); 27 | }; 28 | 29 | export default Work; 30 | -------------------------------------------------------------------------------- /src/components/DrawerComponent.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Drawer, 4 | DrawerBody, 5 | DrawerFooter, 6 | DrawerHeader, 7 | DrawerOverlay, 8 | DrawerContent, 9 | DrawerCloseButton, 10 | Flex, 11 | Text, 12 | } from "@chakra-ui/react"; 13 | 14 | export default function DrawerComponent({ 15 | p = 15, 16 | placement = "right", 17 | width, 18 | isOpen, 19 | children, 20 | onClose, 21 | btnRef, 22 | title = "", 23 | footer, 24 | }) { 25 | return ( 26 | 27 | 33 | 34 | 36 | 37 | 38 | {title} 39 | 40 | {children} 41 | {footer} 42 | 43 | 44 | 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio-website-nextjs", 3 | "version": "1.0.0", 4 | "description": "This is my personal portfolio website.", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "next dev", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "keywords": [], 13 | "author": "Masood Akhtar Vaheed", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@chakra-ui/icons": "^2.1.0", 17 | "@chakra-ui/next-js": "^2.1.5", 18 | "@chakra-ui/portal": "^2.1.0", 19 | "@chakra-ui/react": "^2.8.0", 20 | "@emotion/react": "^11.11.1", 21 | "@emotion/styled": "^11.11.0", 22 | "eslint": "8.47.0", 23 | "eslint-config-next": "13.4.19", 24 | "framer-motion": "^10.15.2", 25 | "mapbox-gl": "^2.15.0", 26 | "next": "13.4.19", 27 | "next-reveal": "^1.0.6", 28 | "react": "18.2.0", 29 | "react-dom": "18.2.0", 30 | "react-hook-form": "^7.45.4", 31 | "react-icons": "^5.2.1", 32 | "react-loader-spinner": "^5.4.5", 33 | "react-tsparticles": "^2.12.2", 34 | "tsparticles": "^2.12.0", 35 | "typed.js": "^2.0.16" 36 | }, 37 | "devDependencies": { 38 | "sass": "^1.64.2" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/components/ClientRootLayout.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import React from "react"; 3 | import Script from "next/script"; 4 | import { Providers } from "./Providers"; 5 | import Header from "./Header"; 6 | import "../styles/main.scss"; 7 | 8 | const ClientRootLayout = ({ children }) => { 9 | return ( 10 | 11 | 16 | 31 | 32 |
33 | {children} 34 | 35 | 36 | 37 | ); 38 | }; 39 | 40 | export default ClientRootLayout; -------------------------------------------------------------------------------- /src/components/SocialIcons.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { socialMediaLinks } from "../utils/constants"; 3 | import { Flex } from "@chakra-ui/react"; 4 | import { Icon } from "@chakra-ui/react"; 5 | import { Link } from "@chakra-ui/next-js"; 6 | 7 | const SocialIcons = () => { 8 | return ( 9 | 15 | {socialMediaLinks.map((linkData, index) => ( 16 | 35 | 36 | 37 | ))} 38 | 39 | ); 40 | }; 41 | 42 | export default SocialIcons; 43 | -------------------------------------------------------------------------------- /src/components/MobileHeader.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useDisclosure, Flex, Button, VStack } from "@chakra-ui/react"; 3 | import DrawerComponent from "./DrawerComponent"; 4 | import { IoMdMenu } from "react-icons/io"; 5 | import { Link } from "@chakra-ui/next-js"; 6 | import React from "react"; 7 | import { links } from "../utils/constants"; 8 | 9 | export default function MobileHeader({ pathname }) { 10 | const { isOpen, onOpen, onClose } = useDisclosure(); 11 | const btnRef = React.useRef(); 12 | 13 | useEffect(() => { 14 | onClose(); 15 | }, [pathname]); 16 | 17 | return ( 18 | 19 | 22 | 23 | 24 | 25 | {links.map((link, index) => ( 26 | 36 | {link.text} 37 | 38 | ))} 39 | 40 | 41 | 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /src/components/Providers.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { CacheProvider } from '@chakra-ui/next-js' 4 | import { ChakraProvider, extendTheme } from '@chakra-ui/react' 5 | 6 | export function Providers({ 7 | children 8 | }) { 9 | 10 | const customTheme = extendTheme({ 11 | config: { 12 | initialColorMode: "dark", 13 | useSystemColorMode: false, 14 | }, 15 | colors: { 16 | blueTheme: { 17 | // current active theme 18 | bg: "#02001E", 19 | navBg: "rgba(10, 25, 47, 0.85)", 20 | navLinkActive:"#64ffda", 21 | navShadow:"rgba(2,12,27,0.7)", 22 | card:"#112240", 23 | cardHover:"#176B87" 24 | }, 25 | defaultTheme:{ 26 | bg: "#02001E", 27 | navBg: "#200b8b3c", 28 | navLinkActive:"#16FF00", 29 | card:"#213363", 30 | cardHover:"#213d8d" 31 | }, 32 | hover:{ 33 | gray:"rgba(0, 0, 0, 0.6)" 34 | }, 35 | social:{ 36 | instagram:"#D53F8C", 37 | instagramHover:"#FF63B4", 38 | linkedin:"#0072b1", 39 | linkedinHover:"#1282B1", 40 | twitter:"#00acee", 41 | twitterHover:"#63C5F4", 42 | hashnode:"#265FF7", 43 | hashnodeHover:"#7A84E6" 44 | } 45 | }, 46 | }); 47 | return ( 48 | 49 | 50 | {children} 51 | 52 | 53 | ) 54 | } -------------------------------------------------------------------------------- /src/app/about/InterestsCard.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import React from "react"; 3 | import { Card, Heading, Icon, Box, useColorModeValue } from "@chakra-ui/react"; 4 | 5 | const InterestsCard = ({ interest, icon }) => { 6 | const cardBg = useColorModeValue("white", "gray.800"); 7 | const borderColor = useColorModeValue("gray.200", "gray.700"); 8 | const iconColor = useColorModeValue("blue.500", "blue.300"); 9 | 10 | return ( 11 | 32 | 42 | 43 | 44 | 49 | {interest} 50 | 51 | 52 | ); 53 | }; 54 | 55 | export default InterestsCard; -------------------------------------------------------------------------------- /src/app/contact/MapBox.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from "react"; 2 | import { 3 | Modal, 4 | ModalOverlay, 5 | ModalContent, 6 | ModalCloseButton, 7 | ModalBody, 8 | Box, 9 | } from "@chakra-ui/react"; 10 | import mapboxgl from "mapbox-gl"; 11 | 12 | const MapBox = ({ isOpen, onClose }) => { 13 | const mapContainer = useRef(null); 14 | const map = useRef(null); 15 | 16 | useEffect(() => { 17 | // Map box was trying to find container and on initial load it was not getting it from the DOM, so it was not rendering. 18 | setTimeout(() => { 19 | if (isOpen) { 20 | mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN; 21 | map.current = new mapboxgl.Map({ 22 | container: mapContainer.current, 23 | style: "mapbox://styles/mapbox/streets-v11", 24 | center: [78.474, 17.385], 25 | zoom: 10, 26 | }); 27 | 28 | } 29 | }); 30 | 31 | return () => { 32 | if (map.current) { 33 | map.current.remove(); 34 | map.current = null; 35 | } 36 | }; 37 | }, [isOpen]); 38 | 39 | return ( 40 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ); 55 | }; 56 | 57 | export default MapBox; 58 | -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | import { query } from "./constants"; 2 | 3 | export const getArticlesData = async () => { 4 | const allArticles = []; 5 | let hasNextPage = true; 6 | let endCursor=""; 7 | 8 | while (hasNextPage) { 9 | const response = await fetch(process.env.NEXT_PUBLIC_HASHNODE_API, { 10 | method: "POST", 11 | headers: { 12 | "Content-Type": "application/json", 13 | }, 14 | body: JSON.stringify({ 15 | query, 16 | variables: { after: endCursor }, 17 | }), 18 | }); 19 | 20 | 21 | const data = await response.json(); 22 | const articles = data.data.publication.posts.edges; 23 | allArticles.push(...articles); 24 | hasNextPage = data.data.publication.posts.pageInfo.hasNextPage; 25 | endCursor = data.data.publication.posts.pageInfo.endCursor; 26 | } 27 | return allArticles; 28 | }; 29 | 30 | export const subscribeToNewsletter = async (email) => { 31 | const publicationId = process.env.NEXT_PUBLIC_HASHNODE_PUBLICATION_ID; 32 | const url = "/newsletter"; 33 | const headers = new Headers(); 34 | headers.append("Content-Type", "application/json"); 35 | 36 | const body = JSON.stringify({ 37 | email, 38 | publicationId, 39 | }); 40 | 41 | const requestOptions = { 42 | method: "POST", 43 | headers, 44 | body, 45 | redirect: "follow", 46 | }; 47 | 48 | try { 49 | const response = await fetch(url, requestOptions); 50 | const result = await response.json(); 51 | return result; 52 | } catch (error) { 53 | console.log("error", error); 54 | throw error; 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import { Flex, HStack, chakra } from "@chakra-ui/react"; 2 | import { Link } from "@chakra-ui/next-js"; 3 | import React from "react"; 4 | import MobileHeader from "./MobileHeader"; 5 | import { links } from "../utils/constants"; 6 | import { usePathname } from "next/navigation"; 7 | 8 | export default function Header() { 9 | const pathname = usePathname(); 10 | 11 | return ( 12 | 21 | 22 | 28 | VAHEED SHAIK {""} {" "} 29 | 30 | 31 | 32 | {links.map((link, index) => ( 33 | 41 | {link.text} 42 | 43 | ))} 44 | 45 | 46 | 47 | 48 | 49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /src/app/blogs/ArticlesCard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Card, 4 | CardBody, 5 | Text, 6 | Button, 7 | Image, 8 | Heading, 9 | Icon, 10 | Box, 11 | } from "@chakra-ui/react"; 12 | import { FaExternalLinkAlt } from "react-icons/fa"; 13 | 14 | const ArticlesCard = (props) => { 15 | const { data, setActiveCard, onOpen } = props; 16 | const { title, coverImage, slug, brief } = data; 17 | const articleUrl = `https://codersk36.hashnode.dev/${slug}`; 18 | return ( 19 | <> 20 | 27 | 28 | Chakra UI 34 | 35 | {title} 36 | 37 | 38 | {brief.substring(0, 100)}... 39 | { 47 | setActiveCard(data) 48 | onOpen(true); 49 | }} 50 | > 51 | Read more 52 | 53 | 54 | 64 | 65 | 66 | 67 | ); 68 | }; 69 | 70 | export default ArticlesCard; 71 | -------------------------------------------------------------------------------- /src/app/projects/ProjectCard.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { Card, ScaleFade, Image, Text, Link, Icon,Flex } from "@chakra-ui/react"; 4 | import { FaLink,FaGithub } from "react-icons/fa6"; 5 | 6 | const ProjectCard = (props) => { 7 | const { title, image, link, source } = props.data; 8 | const [showHover, setShowHover] = useState(false); 9 | const linkHover = {fill:"blueTheme.navLinkActive",transition:"all ease-in-out 0.5s"} 10 | 11 | return ( 12 | 13 | 21 | {title} 22 | 23 | setShowHover(true)} 25 | onMouseLeave={() => setShowHover(false)} 26 | zIndex={0} 27 | boxShadow="0 10px 30px -10px black" 28 | 29 | > 30 | project-img 36 | 49 | { 50 | link !==null ? 51 | 52 | : 53 | null 54 | } 55 | 56 | 57 | 58 | 59 | ); 60 | }; 61 | 62 | export default ProjectCard; 63 | -------------------------------------------------------------------------------- /src/app/projects/page.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import ProjectCard from "./ProjectCard"; 4 | import { 5 | Heading, 6 | SimpleGrid, 7 | HStack, 8 | useRadioGroup, 9 | Center, 10 | Box, 11 | Flex, 12 | } from "@chakra-ui/react"; 13 | import RadioCard from "../../components/RadioCards"; 14 | import { projectsData } from "../../utils/constants"; 15 | import { RevealWrapper } from "next-reveal"; 16 | 17 | const Projects = () => { 18 | const [selectedData, setSelectedData] = useState(projectsData); 19 | const valSelectFn = (value) => 20 | setSelectedData(() => { 21 | return value === "ALL" 22 | ? projectsData 23 | : projectsData.filter((data) => data.type === value); 24 | }); 25 | const options = ["ALL", "WEB-APP", "PROJECT"]; 26 | const { getRootProps, getRadioProps } = useRadioGroup({ 27 | name: "project", 28 | defaultValue: "ALL", 29 | onChange: valSelectFn, 30 | }); 31 | const group = getRootProps(); 32 | 33 | return ( 34 |
35 | 36 | 37 | PROJECTS 38 | 39 | 40 | 41 | 42 | {options.map((value) => { 43 | const radio = getRadioProps({ value }); 44 | return ( 45 | 46 | {value} 47 | 48 | ); 49 | })} 50 | 51 | 52 | 53 | 57 | {selectedData.map((data, index) => { 58 | return ; 59 | })} 60 | 61 | 62 | 63 |
64 | ); 65 | }; 66 | 67 | export default Projects; 68 | -------------------------------------------------------------------------------- /src/app/contact/page.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React,{useEffect} from "react"; 3 | import ContactForm from "./ContactForm"; 4 | import { Heading, Icon, Stack, Text, Tooltip,useDisclosure,Center,SimpleGrid } from "@chakra-ui/react"; 5 | import { IoIosMail } from "react-icons/io"; 6 | import { ImLocation } from "react-icons/im"; 7 | import { Link } from "@chakra-ui/next-js"; 8 | import SocialIcons from "../../components/SocialIcons"; 9 | import MapBox from "./MapBox"; 10 | import { RevealWrapper } from 'next-reveal' 11 | 12 | 13 | const Contact = () => { 14 | const { isOpen, onOpen, onClose } = useDisclosure(); 15 | 16 | return ( 17 |
18 | 19 | 20 | 21 | Let's discuss on something{" "} 22 | 23 | cool 24 | {" "} 25 | together 26 | 27 | 28 | 29 | 30 | 37 | 38 | vaheedsk36@gmail.com 39 | 40 | 41 | 42 | 43 | 44 | 45 | Hyderabad, India 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
56 | ); 57 | }; 58 | 59 | export default Contact; 60 | -------------------------------------------------------------------------------- /public/images/fmr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/particlesjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "particles": { 3 | "number": { 4 | "value": 80, 5 | "density": { 6 | "enable": true, 7 | "value_area": 800 8 | } 9 | }, 10 | "color": { 11 | "value": "#ffffff" 12 | }, 13 | "shape": { 14 | "type": "circle", 15 | "stroke": { 16 | "width": 0, 17 | "color": "#000000" 18 | }, 19 | "polygon": { 20 | "nb_sides": 5 21 | }, 22 | "image": { 23 | "src": "img/github.svg", 24 | "width": 100, 25 | "height": 100 26 | } 27 | }, 28 | "opacity": { 29 | "value": 0.5, 30 | "random": false, 31 | "anim": { 32 | "enable": false, 33 | "speed": 1, 34 | "opacity_min": 0.1, 35 | "sync": false 36 | } 37 | }, 38 | "size": { 39 | "value": 3, 40 | "random": true, 41 | "anim": { 42 | "enable": true, 43 | "speed": 4.795204795204795, 44 | "size_min": 0.1, 45 | "sync": true 46 | } 47 | }, 48 | "line_linked": { 49 | "enable": true, 50 | "distance": 150, 51 | "color": "#ffffff", 52 | "opacity": 0.4, 53 | "width": 1 54 | }, 55 | "move": { 56 | "enable": true, 57 | "speed": 6, 58 | "direction": "none", 59 | "random": false, 60 | "straight": false, 61 | "out_mode": "out", 62 | "bounce": false, 63 | "attract": { 64 | "enable": false, 65 | "rotateX": 600, 66 | "rotateY": 1200 67 | } 68 | } 69 | }, 70 | "interactivity": { 71 | "detect_on": "canvas", 72 | "events": { 73 | "onhover": { 74 | "enable": false, 75 | "mode": "repulse" 76 | }, 77 | "onclick": { 78 | "enable": true, 79 | "mode": "repulse" 80 | }, 81 | "resize": true 82 | }, 83 | "modes": { 84 | "grab": { 85 | "distance": 400, 86 | "line_linked": { 87 | "opacity": 1 88 | } 89 | }, 90 | "bubble": { 91 | "distance": 400, 92 | "size": 40, 93 | "duration": 2, 94 | "opacity": 8, 95 | "speed": 3 96 | }, 97 | "repulse": { 98 | "distance": 200, 99 | "duration": 0.4 100 | }, 101 | "push": { 102 | "particles_nb": 4 103 | }, 104 | "remove": { 105 | "particles_nb": 2 106 | } 107 | } 108 | }, 109 | "retina_detect": true 110 | } 111 | -------------------------------------------------------------------------------- /src/app/layout.jsx: -------------------------------------------------------------------------------- 1 | import Favicon from "/public/images/favicon.png"; 2 | import ClientRootLayout from "../components/ClientRootLayout"; 3 | 4 | export const metadata = { 5 | metadataBase: new URL('https://vaheedshaik.com'), 6 | title: { 7 | default: "Vaheed Shaik | Software Engineer", 8 | template: "%s | Vaheed Shaik" 9 | }, 10 | description: "Welcome to Vaheed's Software Engineering Portfolio. Explore a diverse range of projects and see how I can bring your ideas to life. Let's connect and discuss your next venture!", 11 | keywords: [ 12 | "portfolio", 13 | "app", 14 | "next.js 13", 15 | "sass", 16 | "scss", 17 | "react", 18 | "chakra", 19 | "hashnode", 20 | "best portfolio", 21 | "best portfolio website", 22 | "software engineer", 23 | "web development", 24 | "frontend developer", 25 | "full stack developer", 26 | "javascript", 27 | "typescript", 28 | "react developer", 29 | "nextjs developer", 30 | "portfolio website", 31 | "developer portfolio" 32 | ], 33 | authors: [{ name: "Vaheed Shaik" }], 34 | creator: "Vaheed Shaik", 35 | publisher: "Vaheed Shaik", 36 | formatDetection: { 37 | email: false, 38 | address: false, 39 | telephone: false, 40 | }, 41 | openGraph: { 42 | type: 'website', 43 | locale: 'en_US', 44 | url: 'https://vaheedshaik.com', 45 | title: 'Vaheed Shaik | Software Engineer', 46 | description: 'Welcome to Vaheed\'s Software Engineering Portfolio. Explore a diverse range of projects and see how I can bring your ideas to life. Let\'s connect and discuss your next venture!', 47 | siteName: 'Vaheed Shaik Portfolio', 48 | images: [ 49 | { 50 | url: '/images/og-image.jpg', 51 | width: 1200, 52 | height: 630, 53 | alt: 'Vaheed Shaik Portfolio Preview', 54 | }, 55 | ], 56 | }, 57 | twitter: { 58 | card: 'summary_large_image', 59 | title: 'Vaheed Shaik | Software Engineer', 60 | description: 'Welcome to Vaheed\'s Software Engineering Portfolio. Explore a diverse range of projects and see how I can bring your ideas to life.', 61 | images: ['/images/og-image.jpg'], 62 | creator: '@vaheedshaik', 63 | }, 64 | robots: { 65 | index: true, 66 | follow: true, 67 | googleBot: { 68 | index: true, 69 | follow: true, 70 | 'max-video-preview': -1, 71 | 'max-image-preview': 'large', 72 | 'max-snippet': -1, 73 | }, 74 | }, 75 | icons: [{ 76 | rel: 'icon', 77 | url: Favicon.src, 78 | }], 79 | verification: { 80 | google: 'Dz2xp2RtP9GiXlS5Wj_tzIm0QeRcbzKILqVNJAUAd5w', 81 | yandex: '827e25c6099be3b0', 82 | yahoo: 'EAF9D5ED84139FFD4C2CE4429F37BC3B', 83 | }, 84 | }; 85 | 86 | export default function RootLayout({ children }) { 87 | return {children} 88 | } 89 | -------------------------------------------------------------------------------- /src/app/page.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useEffect, useRef, useCallback } from "react"; 3 | import { Heading, Flex, Center, Image } from "@chakra-ui/react"; 4 | import Typed from "typed.js"; 5 | import SocialIcons from "../components/SocialIcons"; 6 | import Particles from "react-tsparticles"; 7 | import { loadFull } from "tsparticles"; 8 | import particleConfig from "../particlesjs.json"; 9 | import { RevealWrapper } from "next-reveal"; 10 | 11 | export default function Home() { 12 | const typedTextRef = useRef(null); 13 | const particlesInit = useCallback(async (engine) => { 14 | await loadFull(engine); 15 | }, []); 16 | 17 | useEffect(() => { 18 | const options = { 19 | strings: ["Developer", "Coder", "Tech Blogger", "Tech Enthusiast"], 20 | typeSpeed: 50, 21 | backSpeed: 35, 22 | loop: true, 23 | }; 24 | 25 | const typed = new Typed(typedTextRef.current, options); 26 | return () => { 27 | typed.destroy(); 28 | }; 29 | }, []); 30 | 31 | return ( 32 | <> 33 |
34 | 41 | 51 | 52 | profile-image 63 | 64 | 65 | 70 | Hi, my name is 71 | 72 | 73 | 74 | 79 | 83 | Masood Akhtar 84 | 85 | 86 | 91 | Vaheed 92 | 93 | 94 | 95 | 96 | 97 | I 'm 98 | 99 | 100 | 101 | 102 | 103 | 104 |
105 | 106 | ); 107 | } 108 | -------------------------------------------------------------------------------- /src/app/blogs/NewsLetterComponent.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useState } from "react"; 3 | import { 4 | Stack, 5 | FormControl, 6 | Input, 7 | Button, 8 | useColorModeValue, 9 | Heading, 10 | Text, 11 | Container, 12 | Flex, 13 | Modal, 14 | ModalOverlay, 15 | ModalContent, 16 | ModalCloseButton, 17 | ModalBody, 18 | Box, 19 | useDisclosure, 20 | ModalHeader, 21 | } from "@chakra-ui/react"; 22 | import { CheckIcon } from "@chakra-ui/icons"; 23 | import { subscribeToNewsletter } from "../../utils/utils"; 24 | 25 | export default function NewsLetterComponent() { 26 | const [email, setEmail] = useState(""); 27 | const [state, setState] = useState("initial"); 28 | const [error, setError] = useState(false); 29 | const { isOpen, onOpen, onClose } = useDisclosure(); 30 | 31 | return ( 32 | <> 33 | 34 | 35 | 41 | Subscribe to my Newsletter 42 | 43 | { 48 | e.preventDefault(); 49 | setError(false); 50 | setState("submitting"); 51 | subscribeToNewsletter(email) 52 | .then((response) => { 53 | setState(response.result); 54 | onOpen(true); 55 | }) 56 | .catch((error) => { 57 | setError(true); 58 | setState("initial"); 59 | console.error("An error occurred:", error); 60 | }); 61 | }} 62 | > 63 | 64 | setEmail(e.target.value)} 80 | /> 81 | 82 | 83 | 91 | 92 | 93 | 98 | {error 99 | ? "Oh no an error occured! 😢 Please try again later." 100 | : "You won't receive any spam! ✌️"} 101 | 102 | 103 | 104 | 105 | 111 | 112 | 113 | 114 | Thank You for Subscribing 115 | 116 | You have received a confirmation mail to subscribe my hashnode blog 117 | on {email}. Please confirm it, to receive updates on my articles. 118 | 119 | 120 | 121 | 122 | ); 123 | } 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⭐ Personal Portfolio Website ⭐ 2 | 3 | > [Deployed here](https://vaheedshaik.tech/) 4 | 5 | ⭐ Star me on GitHub and do follow ⭐ 6 | 7 | [![Maintenance](https://img.shields.io/badge/maintained-yes-green.svg)](https://github.com/vaheedsk36/portfolio-website-nextjs/commits/main) 8 | [![Website](https://img.shields.io/badge/website-up-yellow)](https://vaheedshaik.tech/) 9 | [![Message](https://img.shields.io/badge/LinkedIn-0077B5?style=flat&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/sk36) 10 | [![License](http://img.shields.io/:license-mit-blue.svg?style=flat&logo)](http://badges.mit-license.org) 11 | 12 | ## Note 13 | 14 | - Latest hashnode graphql version 16.8 syntax is added in this project for getting articles details 15 | 16 | ## Conditions of usage 17 | 18 | - Follow me on [github](https://github.com/vaheedsk36) 19 | - Follow me on [linkedin](https://www.linkedin.com/in/sk36/) (if you want to) 20 | - Star this project on github 21 | 22 | ## Tech Stack and Services Used 🛠️ 23 | 24 | Explore the technologies and services that power this portfolio: 25 | 26 | ![NextJS](https://img.shields.io/badge/next%20js-000000?style=flat&logo=nextdotjs&logoColor=white) 27 | ![ChakraUI](https://img.shields.io/badge/Chakra--UI-319795?style=flat&logo=chakra-ui&logoColor=white) 28 | ![SASS](https://img.shields.io/badge/Sass-CC6699?style=flat&logo=sass&logoColor=white) 29 | ![Google Analytics](https://img.shields.io/badge/Google%20Analytics-E37400?style=flat&logo=google%20analytics&logoColor=white) 30 | ![Vercel](https://img.shields.io/badge/Vercel-000000?style=flat&logo=vercel&logoColor=white) 31 | 32 | ## SEO Enhancements 🚀 33 | 34 | This portfolio is optimized for search engines using several modern SEO techniques: 35 | 36 | - **Comprehensive Metadata:** Uses advanced metadata including OpenGraph, Twitter Card, and extended keywords for better sharing and discoverability. 37 | - **Dynamic Sitemap:** Automatically generates a sitemap at `/sitemap.xml` to help search engines index all main pages (home, about, projects, blogs, contact, skills, certifications, experience). 38 | - **Robots and Verification Tags:** Includes robots directives for indexing and site verification tags for Google, Yandex, and Yahoo. 39 | - **Accessibility & Discoverability:** Metadata and sitemap improve accessibility and ensure all important pages are easily found by search engines. 40 | 41 | For further SEO improvements, you can add structured data (JSON-LD) or extend the sitemap to include dynamic content like blog posts or projects. 42 | 43 | ## Search Engine Verification Tools 🔍 44 | 45 | This project is verified with major search engines using their free webmaster tools: 46 | 47 | ### Google Search Console 48 | - **Purpose:** Monitor and maintain site's presence in Google Search 49 | - **Features:** 50 | - Search performance analytics 51 | - Indexing status 52 | - Mobile usability 53 | - Security issues 54 | - URL inspection 55 | - **Verification Code:** Implemented in metadata 56 | 57 | ### Yandex Webmaster 58 | - **Purpose:** Manage site's presence in Yandex search results 59 | - **Features:** 60 | - Search analytics 61 | - Indexing status 62 | - Crawl statistics 63 | - Site diagnostics 64 | - **Verification Code:** Implemented in metadata 65 | 66 | ### Bing Webmaster Tools 67 | - **Purpose:** Manage site's presence in both Bing and Yahoo search results 68 | - **Features:** 69 | - Search performance 70 | - SEO reports 71 | - URL submission 72 | - Site diagnostics 73 | - **Verification Code:** Implemented in metadata 74 | 75 | All these tools are completely free to use and provide valuable insights for improving your site's search engine presence. 76 | 77 | ## Setup & Deployment Instructions 🚀 78 | 79 | Follow these steps to set up and deploy your own portfolio: 80 | 81 | 1. Fork the repository 82 | 2. Run `npm install` 83 | 3. Make modifications in `app` folder files 84 | 4. Store your image assets in `public > images` 85 | 5. Store you secret keys by in a `.env` file for ref see `.env.sample` 86 | 6. For deployment, follow these [instructions](https://nextjs.org/learn/basics/deploying-nextjs-app/deploy) 87 | 88 | ## Sections 📚 89 | 90 | Explore different sections of my profile: 91 | 92 | - **🏠 Home** 93 | - **🙋‍♂️ About** 94 | - **🛠️ Skills** 95 | - **💼 Projects** 96 | - **🔍 Experience** 97 | - **📝 Blogs** 98 | - **📬 Contact** 99 | 100 | ## Contributing 💡 101 | 102 | To contribute, follow these steps: 103 | 104 | ### Step 1 105 | 106 | Fork or clone this repo to your local machine. 107 | 108 | ### Step 2 109 | 110 | Build your code. Implement your changes, add features, or fix issues. 111 | 112 | ### Step 3 113 | 114 | When you're ready, create a new pull request to merge your changes: 115 | 116 | - 🔃 Push your changes to your forked repo. 117 | - 👀 Await review and address any feedback. 118 | 119 | Thank you for contributing to this repo! Together, we can make it even better. 😄🚀 120 | -------------------------------------------------------------------------------- /src/app/experience/WorkCard.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import { 4 | Card, 5 | CardBody, 6 | Image, 7 | Heading, 8 | Text, 9 | Flex, 10 | Box, 11 | VStack, 12 | Divider, 13 | } from "@chakra-ui/react"; 14 | 15 | const WorkCard = (props) => { 16 | const { company, companyImg, roles } = props.data; 17 | const hasMultipleRoles = roles.length > 1; 18 | 19 | return ( 20 | <> 21 | 29 | 30 | 35 | 42 | Company Logo 54 | 60 | {company} 61 | 62 | 63 | 64 | 70 | 71 | {roles.map((role, index) => ( 72 | 73 | {hasMultipleRoles && index > 0 && ( 74 | 82 | )} 83 | 84 | {hasMultipleRoles && ( 85 | 97 | 98 | {index + 1} 99 | 100 | 101 | )} 102 | 103 | 104 | {role.duration} 105 | 106 | 113 | {role.designation} 114 | 115 |
121 | {role.description} 122 |
123 |
124 |
125 |
126 | ))} 127 |
128 |
129 |
130 |
131 |
132 | 133 | ); 134 | }; 135 | 136 | export default WorkCard; 137 | -------------------------------------------------------------------------------- /src/app/contact/ContactForm.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { 3 | Input, 4 | Textarea, 5 | NumberInput, 6 | NumberInputField, 7 | FormControl, 8 | FormLabel, 9 | FormErrorMessage, 10 | Button, 11 | Card, 12 | CardBody, 13 | useRadioGroup, 14 | Flex, 15 | Heading, 16 | Icon, 17 | Stack 18 | } from "@chakra-ui/react"; 19 | import { BsFillSendFill } from "react-icons/bs"; 20 | import RadioCard from "../../components/RadioCards"; 21 | import { useForm } from "react-hook-form"; 22 | import { useToast } from "@chakra-ui/react"; 23 | import { RevealWrapper } from 'next-reveal' 24 | 25 | const ContactForm = () => { 26 | const toast = useToast(); 27 | const options = ["Web Development", "Hiring", "Freelance", "Other"]; 28 | const [interestedIn, setInterestedIn] = useState("Web Development"); 29 | const { getRootProps, getRadioProps } = useRadioGroup({ 30 | name: "interested", 31 | defaultValue: interestedIn, 32 | onChange: (value) => setInterestedIn(value), 33 | }); 34 | const group = getRootProps(); 35 | const { 36 | handleSubmit, 37 | register, 38 | formState: { errors }, 39 | reset 40 | } = useForm(); 41 | const [isLoading, setIsLoading] = useState(false); 42 | 43 | const onSubmit = async (formData) => { 44 | setIsLoading(true); 45 | formData["interested-in"] = interestedIn; 46 | const formSubmitURL = `https://fabform.io/f/${process.env.NEXT_PUBLIC_FAB_FORM_KEY}`; 47 | try { 48 | const response = await fetch(formSubmitURL, { 49 | method: "POST", 50 | headers: { 51 | "Content-Type": "application/json", 52 | }, 53 | body: JSON.stringify(formData), 54 | }); 55 | 56 | if (!response.ok) { 57 | throw new Error("Unable to send message "); 58 | } 59 | 60 | reset({ 61 | name: "", 62 | email: "", 63 | number: "", 64 | message: "", 65 | }); 66 | 67 | setIsLoading(false); 68 | 69 | toast({ 70 | title: "Message sent successfully", 71 | status: "success", 72 | position: "top", 73 | duration: 9000, 74 | isClosable: true, 75 | }); 76 | } catch (error) { 77 | console.error("Error sending message:", error); 78 | toast({ 79 | title: error.message, 80 | status: "error", 81 | position: "top", 82 | duration: 9000, 83 | isClosable: true, 84 | }); 85 | } 86 | }; 87 | 88 | return ( 89 | <> 90 | 91 | 92 | 93 | 94 | I'm interested in... 95 | 96 | 97 | {options.map((value) => { 98 | const radio = getRadioProps({ value }); 99 | return ( 100 | 101 | {value} 102 | 103 | ); 104 | })} 105 | 106 | 107 | 108 | Enter Name 109 | 116 | {errors.name && ( 117 | Enter your name 118 | )} 119 | 120 | 121 | Enter Email 122 | 129 | {errors.email && ( 130 | Enter your email 131 | )} 132 | 133 | 134 | Enter Phone No. 135 | 136 | 140 | 141 | 142 | 143 | Enter Message 144 |