├── public ├── s.jpg ├── rmtdev.png ├── hero1 (1).jpg ├── hero1 (2).jpg ├── hero1 (3).jpg ├── corpcomment.png ├── wordanalytics.png ├── portfolio Cover.png ├── GYm Training-main.png ├── Proffesional Cover.png ├── Restraunant Cover.png ├── favicon-1024 (2).png └── Cubex-Website Builder Cover.png ├── lib ├── types.ts ├── utils.ts ├── hooks.ts └── data.ts ├── postcss.config.js ├── .eslintrc.json ├── next.config.js ├── components ├── section-heading.tsx ├── section-divider.tsx ├── footer.tsx ├── theme-switch.tsx ├── projects.tsx ├── submit-btn.tsx ├── skills.tsx ├── about.tsx ├── experience.tsx ├── contact.tsx ├── project.tsx ├── header.tsx └── intro.tsx ├── .gitignore ├── app ├── globals.css ├── page.tsx └── layout.tsx ├── tailwind.config.js ├── tsconfig.json ├── package.json ├── email └── contact-form-email.tsx ├── actions └── sendEmail.ts ├── README.md └── context ├── active-section-context.tsx └── theme-context.tsx /public/s.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/s.jpg -------------------------------------------------------------------------------- /public/rmtdev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/rmtdev.png -------------------------------------------------------------------------------- /public/hero1 (1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/hero1 (1).jpg -------------------------------------------------------------------------------- /public/hero1 (2).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/hero1 (2).jpg -------------------------------------------------------------------------------- /public/hero1 (3).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/hero1 (3).jpg -------------------------------------------------------------------------------- /public/corpcomment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/corpcomment.png -------------------------------------------------------------------------------- /public/wordanalytics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/wordanalytics.png -------------------------------------------------------------------------------- /lib/types.ts: -------------------------------------------------------------------------------- 1 | import { links } from "./data"; 2 | 3 | export type SectionName = (typeof links)[number]["name"]; 4 | -------------------------------------------------------------------------------- /public/portfolio Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/portfolio Cover.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/GYm Training-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/GYm Training-main.png -------------------------------------------------------------------------------- /public/Proffesional Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/Proffesional Cover.png -------------------------------------------------------------------------------- /public/Restraunant Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/Restraunant Cover.png -------------------------------------------------------------------------------- /public/favicon-1024 (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/favicon-1024 (2).png -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { 4 | "react/no-unescaped-entities": 0 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/Cubex-Website Builder Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqtidartara/portfolio-website/HEAD/public/Cubex-Website Builder Cover.png -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | remotePatterns: [ 5 | { 6 | protocol: "https", 7 | hostname: "images.unsplash.com", 8 | }, 9 | ], 10 | }, 11 | experimental: { 12 | serverActions: true, 13 | }, 14 | }; 15 | 16 | module.exports = nextConfig; 17 | -------------------------------------------------------------------------------- /components/section-heading.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | type SectionHeadingProps = { 4 | children: React.ReactNode; 5 | }; 6 | 7 | export default function SectionHeading({ children }: SectionHeadingProps) { 8 | return ( 9 |

10 | {children} 11 |

12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /components/section-divider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { motion } from "framer-motion"; 5 | 6 | export default function SectionDivider() { 7 | return ( 8 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html { 6 | --line-color: #e5e7eb; 7 | } 8 | 9 | html.dark { 10 | --line-color: rgba(255, 255, 255, 0.2); 11 | } 12 | 13 | .borderBlack { 14 | @apply border border-black/10; 15 | } 16 | .background{ 17 | background-color: #ab4b83; 18 | background-image: linear-gradient(225deg, #ab4b83 0%, #2B86C5 50%, #784BA0 100%); 19 | 20 | } 21 | .darkBackground{ 22 | background-image: radial-gradient( circle farthest-corner at 10% 20%, rgba(100,43,115,1) 0%, rgba(4,0,4,1) 90% ); 23 | } 24 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./pages/**/*.{js,ts,jsx,tsx,mdx}", 5 | "./components/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./app/**/*.{js,ts,jsx,tsx,mdx}", 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 12 | "gradient-conic": 13 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | darkMode: "class", 19 | }; 20 | -------------------------------------------------------------------------------- /components/footer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function Footer() { 4 | return ( 5 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import About from "@/components/about"; 2 | import Contact from "@/components/contact"; 3 | import Experience from "@/components/experience"; 4 | import Intro from "@/components/intro"; 5 | import Projects from "@/components/projects"; 6 | import SectionDivider from "@/components/section-divider"; 7 | import Skills from "@/components/skills"; 8 | 9 | export default function Home() { 10 | return ( 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /components/theme-switch.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useTheme } from "@/context/theme-context"; 4 | import React from "react"; 5 | import { BsMoon, BsSun } from "react-icons/bs"; 6 | 7 | export default function ThemeSwitch() { 8 | const { theme, toggleTheme } = useTheme(); 9 | 10 | return ( 11 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | export const validateString = ( 2 | value: unknown, 3 | maxLength: number 4 | ): value is string => { 5 | if (!value || typeof value !== "string" || value.length > maxLength) { 6 | return false; 7 | } 8 | 9 | return true; 10 | }; 11 | 12 | export const getErrorMessage = (error: unknown): string => { 13 | let message: string; 14 | 15 | if (error instanceof Error) { 16 | message = error.message; 17 | } else if (error && typeof error === "object" && "message" in error) { 18 | message = String(error.message); 19 | } else if (typeof error === "string") { 20 | message = error; 21 | } else { 22 | message = "Something went wrong"; 23 | } 24 | 25 | return message; 26 | }; 27 | -------------------------------------------------------------------------------- /lib/hooks.ts: -------------------------------------------------------------------------------- 1 | import { useActiveSectionContext } from "@/context/active-section-context"; 2 | import { useEffect } from "react"; 3 | import { useInView } from "react-intersection-observer"; 4 | import type { SectionName } from "./types"; 5 | 6 | export function useSectionInView(sectionName: SectionName, threshold = 0.75) { 7 | const { ref, inView } = useInView({ 8 | threshold, 9 | }); 10 | const { setActiveSection, timeOfLastClick } = useActiveSectionContext(); 11 | 12 | useEffect(() => { 13 | if (inView && Date.now() - timeOfLastClick > 1000) { 14 | setActiveSection(sectionName); 15 | } 16 | }, [inView, setActiveSection, timeOfLastClick, sectionName]); 17 | 18 | return { 19 | ref, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /components/projects.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import SectionHeading from "./section-heading"; 5 | import { projectsData } from "@/lib/data"; 6 | import Project from "./project"; 7 | import { useSectionInView } from "@/lib/hooks"; 8 | 9 | export default function Projects() { 10 | const { ref } = useSectionInView("Projects", 0.5); 11 | 12 | return ( 13 |
14 | My projects 15 |
16 | {projectsData.map((project, index) => ( 17 | 18 | 19 | 20 | ))} 21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /components/submit-btn.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { FaPaperPlane } from "react-icons/fa"; 3 | import { experimental_useFormStatus as useFormStatus } from "react-dom"; 4 | 5 | export default function SubmitBtn() { 6 | const { pending } = useFormStatus(); 7 | 8 | return ( 9 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@react-email/components": "^0.0.7", 13 | "@react-email/tailwind": "^0.0.8", 14 | "@types/node": "20.3.2", 15 | "@types/react": "18.2.14", 16 | "@types/react-dom": "18.2.6", 17 | "autoprefixer": "10.4.14", 18 | "clsx": "^1.2.1", 19 | "eslint": "8.43.0", 20 | "eslint-config-next": "13.4.7", 21 | "framer-motion": "^10.12.17", 22 | "next": "13.4.8", 23 | "postcss": "8.4.24", 24 | "react": "18.2.0", 25 | "react-dom": "18.2.0", 26 | "react-hot-toast": "^2.4.1", 27 | "react-icons": "^4.10.1", 28 | "react-intersection-observer": "^9.5.2", 29 | "react-vertical-timeline-component": "^3.6.0", 30 | "resend": "^0.16.0", 31 | "tailwindcss": "3.3.2", 32 | "typescript": "5.1.5" 33 | }, 34 | "devDependencies": { 35 | "@types/react-vertical-timeline-component": "^3.3.3" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /email/contact-form-email.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Html, 4 | Body, 5 | Head, 6 | Heading, 7 | Hr, 8 | Container, 9 | Preview, 10 | Section, 11 | Text, 12 | } from "@react-email/components"; 13 | import { Tailwind } from "@react-email/tailwind"; 14 | 15 | type ContactFormEmailProps = { 16 | message: string; 17 | senderEmail: string; 18 | }; 19 | 20 | export default function ContactFormEmail({ 21 | message, 22 | senderEmail, 23 | }: ContactFormEmailProps) { 24 | return ( 25 | 26 | 27 | New message from your portfolio site 28 | 29 | 30 | 31 |
32 | 33 | You received the following message from the contact form 34 | 35 | {message} 36 |
37 | The sender's email is: {senderEmail} 38 |
39 |
40 | 41 |
42 | 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /actions/sendEmail.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import React from "react"; 4 | import { Resend } from "resend"; 5 | import { validateString, getErrorMessage } from "@/lib/utils"; 6 | import ContactFormEmail from "@/email/contact-form-email"; 7 | 8 | const resend = new Resend(process.env.RESEND_API_KEY); 9 | 10 | export const sendEmail = async (formData: FormData) => { 11 | const senderEmail = formData.get("senderEmail"); 12 | const message = formData.get("message"); 13 | 14 | // simple server-side validation 15 | if (!validateString(senderEmail, 500)) { 16 | return { 17 | error: "Invalid sender email", 18 | }; 19 | } 20 | if (!validateString(message, 5000)) { 21 | return { 22 | error: "Invalid message", 23 | }; 24 | } 25 | 26 | let data; 27 | try { 28 | data = await resend.emails.send({ 29 | from: "Contact Form ", 30 | to: "bytegrad@gmail.com", 31 | subject: "Message from contact form", 32 | reply_to: senderEmail, 33 | react: React.createElement(ContactFormEmail, { 34 | message: message, 35 | senderEmail: senderEmail, 36 | }), 37 | }); 38 | } catch (error: unknown) { 39 | return { 40 | error: getErrorMessage(error), 41 | }; 42 | } 43 | 44 | return { 45 | data, 46 | }; 47 | }; 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Watch tutorial here](https://img.youtube.com/vi/sUKptmUVIBM/0.jpg)](https://youtu.be/sUKptmUVIBM) 2 | 3 | # [Watch video here](https://youtu.be/sUKptmUVIBM) 4 | 5 | ## What you will learn 6 | 7 | - Latest Next.js 13 features 8 | - Next.js App Router 9 | - Next.js Server Actions 10 | - Client & Server Components 11 | - TypeScript (Beginner & Intermediate) 12 | - Tailwind CSS 13 | - Context API 14 | - Advanced Animations with Framer Motion 15 | - React.Email & Resend 16 | - Custom React hooks 17 | - Fresh, modern UI design 18 | - Light & Dark mode 19 | - Responsive website 20 | 21 | ## Important 22 | 23 | If you want to be a professional developer, you have to know the fundamentals like JavaScript and CSS really well. I highly recommend you go through my [Professional JavaScript](https://www.udemy.com/course/professional-javascript-course/?referralCode=0C1D5752923168BC87C2) and [Professional CSS](https://www.udemy.com/course/professional-css/?referralCode=4C3C08E82629E6B15752) courses. 24 | 25 | I'm close to releasing a complete React & Next.js course. Get on the email list to receive early-bird pricing: [link](https://email.bytegrad.com/). 26 | 27 | ## Setup 28 | 29 | 1. Add RESEND_API_KEY environment variable in .env.local 30 | 2. In the send-email.ts action file, change the "to" email to your own email 31 | # portfolio-website 32 | # portfolio-website 33 | -------------------------------------------------------------------------------- /components/skills.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import SectionHeading from "./section-heading"; 5 | import { skillsData } from "@/lib/data"; 6 | import { useSectionInView } from "@/lib/hooks"; 7 | import { motion } from "framer-motion"; 8 | 9 | const fadeInAnimationVariants = { 10 | initial: { 11 | opacity: 0, 12 | y: 100, 13 | }, 14 | animate: (index: number) => ({ 15 | opacity: 1, 16 | y: 0, 17 | transition: { 18 | delay: 0.05 * index, 19 | }, 20 | }), 21 | }; 22 | 23 | export default function Skills() { 24 | const { ref } = useSectionInView("Skills"); 25 | 26 | return ( 27 |
32 | My skills 33 | 50 |
51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /context/active-section-context.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import type { SectionName } from "@/lib/types"; 4 | import React, { useState, createContext, useContext } from "react"; 5 | 6 | type ActiveSectionContextProviderProps = { 7 | children: React.ReactNode; 8 | }; 9 | 10 | type ActiveSectionContextType = { 11 | activeSection: SectionName; 12 | setActiveSection: React.Dispatch>; 13 | timeOfLastClick: number; 14 | setTimeOfLastClick: React.Dispatch>; 15 | }; 16 | 17 | export const ActiveSectionContext = 18 | createContext(null); 19 | 20 | export default function ActiveSectionContextProvider({ 21 | children, 22 | }: ActiveSectionContextProviderProps) { 23 | const [activeSection, setActiveSection] = useState("Home"); 24 | const [timeOfLastClick, setTimeOfLastClick] = useState(0); // we need to keep track of this to disable the observer temporarily when user clicks on a link 25 | 26 | return ( 27 | 35 | {children} 36 | 37 | ); 38 | } 39 | 40 | export function useActiveSectionContext() { 41 | const context = useContext(ActiveSectionContext); 42 | 43 | if (context === null) { 44 | throw new Error( 45 | "useActiveSectionContext must be used within an ActiveSectionContextProvider" 46 | ); 47 | } 48 | 49 | return context; 50 | } 51 | -------------------------------------------------------------------------------- /components/about.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import SectionHeading from "./section-heading"; 5 | import { motion } from "framer-motion"; 6 | import { useSectionInView } from "@/lib/hooks"; 7 | 8 | export default function About() { 9 | const { ref } = useSectionInView("About"); 10 | 11 | return ( 12 | 20 | About me 21 | 22 |

23 | I'm a passionate web developer who specializes in bringing creative ideas to life using the power of technology. With expertise in React, Node.js, and Next.js, I craft seamless websites that not only look great but also function flawlessly across all devices. I'm well-versed in TypeScript and JavaScript, utilizing their capabilities to create dynamic and interactive experiences. My proficiency extends to using tools like Tailwind CSS, Framer Motion, and Remotion to enhance user interfaces.I ensure that data-driven applications are as robust as they are visually appealing. Let's collaborate to turn your digital aspirations into reality{" "} 24 |

25 | 26 |

27 | When I' 28 | m not coding, I enjoy 29 | watching tutorials, and reasearch about new development things. I also enjoy{" "} 30 | learning new things. I am currently 31 | learning about{" "} 32 | AI's and Api's 33 |

34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import Header from "@/components/header"; 2 | import "./globals.css"; 3 | import { Inter } from "next/font/google"; 4 | import ActiveSectionContextProvider from "@/context/active-section-context"; 5 | import Footer from "@/components/footer"; 6 | import ThemeSwitch from "@/components/theme-switch"; 7 | import ThemeContextProvider from "@/context/theme-context"; 8 | import { Toaster } from "react-hot-toast"; 9 | 10 | const inter = Inter({ subsets: ["latin"] }); 11 | 12 | export const metadata = { 13 | icons:"/favicon-1024 (2).png", 14 | title: "Iqtidar| Portfolio", 15 | description: "I am a froent-end developer with 1.5 years of experience.", 16 | }; 17 | 18 | export default function RootLayout({ 19 | children, 20 | }: { 21 | children: React.ReactNode; 22 | }) { 23 | return ( 24 | 25 | 28 |
29 |
30 | 31 | 32 | 33 |
34 | {children} 35 |