├── .env.sample ├── .eslintrc.json ├── .gitignore ├── README.md ├── components.json ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── og-image.png └── portfolioLogo.png ├── src ├── app │ ├── about │ │ └── page.tsx │ ├── contact │ │ └── page.tsx │ ├── education │ │ └── page.tsx │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ ├── loading.tsx │ ├── more │ │ └── page.tsx │ ├── page.tsx │ ├── projects │ │ └── page.tsx │ └── skills │ │ └── page.tsx ├── components │ ├── Aboutfooter.tsx │ ├── ContactForm.tsx │ ├── DownLoadResumeBtn.tsx │ ├── Heading.tsx │ ├── HeroImage.tsx │ ├── HeroTexts.tsx │ ├── Navbar.tsx │ ├── ProjectsCard.tsx │ ├── SendEmail.ts │ ├── SkillsFotter.tsx │ ├── SocialLinks.tsx │ ├── TextRotator.tsx │ ├── animation │ │ ├── DockAnimation.tsx │ │ ├── FramerWrapper.tsx │ │ ├── GithubBtn.tsx │ │ └── HackerBtn.tsx │ └── ui │ │ ├── badge.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ └── tooltip.tsx ├── config │ └── portfolio.config.ts └── lib │ └── utils.ts ├── tailwind.config.ts └── tsconfig.json /.env.sample: -------------------------------------------------------------------------------- 1 | RESEND_API_KEY= Your Render Api Key 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project Portfolio 2 | 3 | A simple and Beautiful Porfolio made with Nextjs and Shadcn Ui. 4 | 5 | ![Demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7eq68h0uvs6xqgw3yqe.jpeg) 6 | 7 | ## Getting Started 8 | 9 | First, run the development server: 10 | 11 | ```bash 12 | npm run dev 13 | # or 14 | yarn dev 15 | # or 16 | pnpm dev 17 | # or 18 | bun dev 19 | ``` 20 | 21 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 22 | 23 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 24 | 25 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 26 | 27 | ## Configuration 28 | 29 | This project uses a centralized configuration approach for all personal information. The main configuration file is located at: 30 | 31 | ``` 32 | src/config/portfolio.config.ts 33 | ``` 34 | 35 | ### Configuration Structure 36 | 37 | The configuration file contains the following sections: 38 | 39 | - **Basic Information**: Name, title, description, location 40 | - **Contact Information**: Email and other contact details 41 | - **Social Media Links**: Links to various social media profiles 42 | - **SEO Information**: Keywords, metadata, and SEO-related settings 43 | - **About Information**: Bio, hobbies, and personal details 44 | - **Skills**: Programming languages, frameworks, tools, and professional roles 45 | - **Education**: Academic background and qualifications 46 | - **Projects**: Portfolio of projects with descriptions and links 47 | - **More Links**: Additional external links and resources 48 | 49 | ### Customizing Your Portfolio 50 | 51 | To personalize the portfolio, simply edit the values in the `portfolio.config.ts` file. All changes will be reflected throughout the site automatically without having to modify multiple files. 52 | 53 | Example usage in a component: 54 | 55 | ```typescript 56 | import { portfolioConfig } from "@/config/portfolio.config"; 57 | 58 | // Access configuration values 59 | const { name, title } = portfolioConfig; 60 | ``` 61 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | experimental:{ 4 | serverComponentsExternalPackages: [ 5 | '@react-email/render', 6 | ], 7 | // images:{ 8 | // remotePatterns:[ 9 | // { 10 | // protocol: 'https', 11 | // hostname: 'cdn.jsdelivr.net', 12 | // } 13 | // ] 14 | // } 15 | } 16 | } 17 | 18 | module.exports = nextConfig 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 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 | "@radix-ui/react-label": "^2.0.2", 13 | "@radix-ui/react-toast": "^1.1.5", 14 | "@radix-ui/react-tooltip": "^1.0.7", 15 | "@vercel/og": "^0.5.20", 16 | "class-variance-authority": "^0.7.0", 17 | "clsx": "^2.0.0", 18 | "framer-motion": "^11.2.13", 19 | "lucide-react": "^0.292.0", 20 | "next": "^15.0.3", 21 | "react": "^18.3.1", 22 | "react-dom": "^18.3.1", 23 | "resend": "^0.16.0", 24 | "tailwind-merge": "^2.0.0", 25 | "tailwindcss-animate": "^1.0.7" 26 | }, 27 | "devDependencies": { 28 | "@types/node": "^20", 29 | "@types/react": "^18", 30 | "@types/react-dom": "^18", 31 | "autoprefixer": "^10.0.1", 32 | "eslint": "^8", 33 | "eslint-config-next": "14.0.2", 34 | "postcss": "^8", 35 | "tailwindcss": "^3.3.0", 36 | "typescript": "^5" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taqui-786/Portfolio/13a1ff256737e5fa2a781b77da6510c856572b4b/public/og-image.png -------------------------------------------------------------------------------- /public/portfolioLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taqui-786/Portfolio/13a1ff256737e5fa2a781b77da6510c856572b4b/public/portfolioLogo.png -------------------------------------------------------------------------------- /src/app/about/page.tsx: -------------------------------------------------------------------------------- 1 | import Aboutfooter from "@/components/Aboutfooter"; 2 | import FramerWrapper from "@/components/animation/FramerWrapper"; 3 | import Heading from "@/components/Heading"; 4 | import { Badge } from "@/components/ui/badge"; 5 | import { Circle, Heart, User2 } from "lucide-react"; 6 | import { portfolioConfig } from "@/config/portfolio.config"; 7 | 8 | const page = () => { 9 | const items = portfolioConfig.about.hobbies.map((hobby) => ({ hobby })); 10 | 11 | return ( 12 | // ABOUT PAGE 13 |
14 | 15 | 16 | About me 17 | 18 |
19 | 20 | {portfolioConfig.title} And Web
Developer, Based In{" "} 21 | {portfolioConfig.about.personalInfo.nationality}. 22 |
23 | 24 | 25 |

26 | {portfolioConfig.about.bio} 27 |

28 |
29 |
30 | 35 | 36 | 37 | 38 |

39 | {" "} 40 | Hobbies 41 |

42 |
43 | {items.map((val, indx) => { 44 | return ( 45 |
49 | {val.hobby} 50 |
51 | ); 52 | })} 53 |
54 |
55 |
56 | ); 57 | }; 58 | 59 | export default page; 60 | -------------------------------------------------------------------------------- /src/app/contact/page.tsx: -------------------------------------------------------------------------------- 1 | import ContactForm from "@/components/ContactForm"; 2 | import FramerWrapper from "@/components/animation/FramerWrapper"; 3 | import Heading from "@/components/Heading"; 4 | import { Badge } from "@/components/ui/badge"; 5 | import { Phone } from "lucide-react"; 6 | 7 | const contactPage = () => { 8 | return ( 9 | // PROJECT PAGE 10 |
11 | 12 | 13 | Contact Us 14 | 15 |
16 | Contact Me! 17 |
18 | 19 | 20 | 21 |
22 |

23 |
24 |
25 | ); 26 | }; 27 | 28 | export default contactPage; 29 | -------------------------------------------------------------------------------- /src/app/education/page.tsx: -------------------------------------------------------------------------------- 1 | import FramerWrapper from "@/components/animation/FramerWrapper"; 2 | import Heading from "@/components/Heading"; 3 | import { Badge } from "@/components/ui/badge"; 4 | import { Briefcase } from "lucide-react"; 5 | import { portfolioConfig } from "@/config/portfolio.config"; 6 | 7 | const educationPage = () => { 8 | return ( 9 | // ABOUT PAGE 10 |
11 | 12 | 13 | Education 14 | 15 |
16 | My Education 17 |
18 |
19 | {portfolioConfig.education.map((edu, index) => ( 20 |
21 | 27 | {edu.period} 28 | 29 | 35 |
36 | {edu.degree},
{edu.institution} 37 |
38 |

39 | {edu.description} 40 |

41 |
42 |
43 | ))} 44 |
45 |
46 | ); 47 | }; 48 | 49 | export default educationPage; 50 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taqui-786/Portfolio/13a1ff256737e5fa2a781b77da6510c856572b4b/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | 6 | @layer base { 7 | :root { 8 | --background: 0 0% 100%; 9 | --foreground: 222.2 84% 4.9%; 10 | 11 | --card: 0 0% 100%; 12 | --card-foreground: 222.2 84% 4.9%; 13 | 14 | --popover: 0 0% 100%; 15 | --popover-foreground: 222.2 84% 4.9%; 16 | 17 | --primary: 222.2 47.4% 11.2%; 18 | --primary-foreground: 210 40% 98%; 19 | --primary-sky: 216.24deg 89.95% 57.06%; 20 | 21 | --secondary: 210 40% 96.1%; 22 | --secondary-foreground: 222.2 47.4% 11.2%; 23 | 24 | --muted: 210 40% 96.1%; 25 | --muted-foreground: 215.4 16.3% 46.9%; 26 | 27 | --accent: 210 40% 96.1%; 28 | --accent-foreground: 222.2 47.4% 11.2%; 29 | 30 | --destructive: 0 84.2% 60.2%; 31 | --destructive-foreground: 210 40% 98%; 32 | 33 | --border: 214.3 31.8% 91.4%; 34 | --input: 214.3 31.8% 91.4%; 35 | --ring: 222.2 84% 4.9%; 36 | 37 | --radius: 0.5rem; 38 | } 39 | 40 | .dark { 41 | --background: 222.2 84% 4.9%; 42 | --foreground: 210 40% 98%; 43 | 44 | --card: 222.2 84% 4.9%; 45 | --card-foreground: 210 40% 98%; 46 | 47 | --popover: 222.2 84% 4.9%; 48 | --popover-foreground: 210 40% 98%; 49 | 50 | --primary: 210 40% 98%; 51 | --primary-foreground: 222.2 47.4% 11.2%; 52 | 53 | --secondary: 217.2 32.6% 17.5%; 54 | --secondary-foreground: 210 40% 98%; 55 | 56 | --muted: 217.2 32.6% 17.5%; 57 | --muted-foreground: 215 20.2% 65.1%; 58 | 59 | --accent: 217.2 32.6% 17.5%; 60 | --accent-foreground: 210 40% 98%; 61 | 62 | --destructive: 0 62.8% 30.6%; 63 | --destructive-foreground: 210 40% 98%; 64 | 65 | --border: 217.2 32.6% 17.5%; 66 | --input: 217.2 32.6% 17.5%; 67 | --ring: 212.7 26.8% 83.9%; 68 | } 69 | } 70 | 71 | @layer base { 72 | * { 73 | @apply border-border; 74 | } 75 | body { 76 | @apply bg-background text-foreground; 77 | } 78 | } 79 | 80 | /* CUSTOM CSS */ 81 | .name_underline::after{ 82 | content: ""; 83 | display: block; 84 | width: 6rem; 85 | height: .6rem; 86 | background-color: hsl(var(--primary-sky)); 87 | } 88 | .icon_underline::after{ 89 | content: ""; 90 | position: absolute; 91 | top: 100%; 92 | display: block; 93 | width: 2rem; 94 | height: .3rem; 95 | background-color: hsl(var(--primary-sky)); 96 | margin-bottom: 2rem; 97 | } 98 | .education_point::before{ 99 | content: ""; 100 | display: block; 101 | position: absolute; 102 | top: 46.7%; 103 | left: -7px; 104 | width: 10px; 105 | height: 10px; 106 | border-radius: 50%; 107 | background-color: hsl(var(--primary-sky)); 108 | outline: 3px solid hsl(var(--primary)); 109 | box-shadow: 0 2px 5px 2px hsl(var(--primary-sky)); 110 | } 111 | /* TEXT ROTATOR STYLES */ 112 | .animate-text-slide { 113 | animation: text-slide 12.5s cubic-bezier(0.83, 0, 0.17, 1) infinite; 114 | } 115 | 116 | @keyframes text-slide { 117 | 0%, 118 | 16% { 119 | transform: translateY(0%); 120 | } 121 | 122 | 20%, 123 | 36% { 124 | transform: translateY(-16.66%); 125 | } 126 | 127 | 40%, 128 | 56% { 129 | transform: translateY(-33.33%); 130 | } 131 | 132 | 60%, 133 | 76% { 134 | transform: translateY(-50%); 135 | } 136 | 137 | 80%, 138 | 96% { 139 | transform: translateY(-66.66%); 140 | } 141 | 142 | 100% { 143 | transform: translateY(-83.33%); 144 | } 145 | } -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Poppins, Rubik } from "next/font/google"; 3 | import "./globals.css"; 4 | import { cn } from "@/lib/utils"; 5 | import Navbar from "@/components/Navbar"; 6 | import { portfolioConfig } from "@/config/portfolio.config"; 7 | 8 | const poppins = Poppins({ 9 | subsets: ["latin"], 10 | weight: "400", 11 | variable: "--font-poppins", 12 | }); 13 | const rubik = Rubik({ 14 | subsets: ["latin"], 15 | weight: "600", 16 | variable: "--font-rubik", 17 | }); 18 | 19 | export const metadata: Metadata = { 20 | metadataBase: new URL(portfolioConfig.seo.url), 21 | title: { 22 | default: portfolioConfig.name, 23 | template: `%s - ${portfolioConfig.title}`, 24 | }, 25 | description: portfolioConfig.description, 26 | 27 | // added new keywords for seo 28 | keywords: portfolioConfig.seo.keywords, 29 | authors: portfolioConfig.seo.authors, 30 | creator: portfolioConfig.name, 31 | 32 | openGraph: { 33 | type: "website", 34 | locale: "en_US", 35 | url: portfolioConfig.seo.url, 36 | title: portfolioConfig.name, 37 | description: portfolioConfig.description, 38 | images: [`${portfolioConfig.seo.url}/og-image.png`], 39 | siteName: portfolioConfig.name, 40 | }, 41 | twitter: { 42 | card: "summary_large_image", 43 | title: portfolioConfig.name, 44 | description: portfolioConfig.description, 45 | images: [`${portfolioConfig.seo.url}/og-image.png`], 46 | creator: portfolioConfig.seo.twitterHandle, 47 | }, 48 | icons: { 49 | icon: "/favicon.ico", 50 | }, 51 | }; 52 | 53 | export default function RootLayout({ 54 | children, 55 | }: { 56 | children: React.ReactNode; 57 | }) { 58 | return ( 59 | 60 | 61 |
67 | {/* NAVBAR -> */} 68 | 69 | {children} 70 |
71 | 72 | 73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /src/app/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Loader } from "lucide-react"; 2 | 3 | 4 | export default function Loading() { 5 | return ( 6 | 7 | 8 | ) 9 | } -------------------------------------------------------------------------------- /src/app/more/page.tsx: -------------------------------------------------------------------------------- 1 | import Heading from "@/components/Heading"; 2 | import { Badge } from "@/components/ui/badge"; 3 | import { ExternalLink, PackagePlus } from "lucide-react"; 4 | import { 5 | Card, 6 | CardContent, 7 | CardFooter, 8 | CardHeader, 9 | CardTitle, 10 | } from "@/components/ui/card"; 11 | import Link from "next/link"; 12 | import { cn } from "@/lib/utils"; 13 | import { buttonVariants } from "@/components/ui/button"; 14 | import FramerWrapper from "@/components/animation/FramerWrapper"; 15 | import { portfolioConfig } from "@/config/portfolio.config"; 16 | 17 | const morePage = () => { 18 | return ( 19 | // ABOUT PAGE 20 |
21 | 22 | 23 | More 24 | 25 |
26 | More 27 |
28 |
29 | {portfolioConfig.moreLinks.map((value, indx) => { 30 | return ( 31 | 39 | 40 | 41 | {value.title} 42 | 43 | 44 |

{value.description}

45 |
46 | 47 | 55 | {" "} 56 | 57 | Visit here 58 | 59 | 60 |
61 |
62 | ); 63 | })} 64 |
65 |
66 | ); 67 | }; 68 | 69 | export default morePage; 70 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import SocialLinks from "@/components/SocialLinks"; 2 | import HeroTexts from "@/components/HeroTexts"; 3 | import HeroImage from "@/components/HeroImage"; 4 | import GithubBtn from "@/components/animation/GithubBtn"; 5 | import DownLoadResumeBtn from "@/components/DownLoadResumeBtn"; 6 | import FramerWrapper from "@/components/animation/FramerWrapper"; 7 | 8 | 9 | export default function Home() { 10 | return ( 11 | <> 12 | {/* LEFT SIDE */} 13 | 18 | 19 |
20 | 21 |
22 | 23 |
24 | {/* RIGHT SIDE image */} 25 | 30 | {/* IMAGE */} 31 | 32 | 33 | 34 | {/* GITHUB BUTTON */} 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/app/projects/page.tsx: -------------------------------------------------------------------------------- 1 | import FramerWrapper from "@/components/animation/FramerWrapper"; 2 | import Heading from "@/components/Heading"; 3 | import ProjectCards from "@/components/ProjectsCard"; 4 | import { Badge } from "@/components/ui/badge"; 5 | import { Layers } from "lucide-react"; 6 | import { portfolioConfig } from "@/config/portfolio.config"; 7 | 8 | const projectsPage = () => { 9 | return ( 10 | // PROJECT PAGE 11 |
12 | 13 | 14 | Projects 15 | 16 |
17 | My Projects 18 | 19 |

20 | I love to Build Cool Projects. Here, you'll find a curated 21 | collection of my creative endeavors and technical projects. Each 22 | piece represents a journey of innovation, problem-solving, and 23 | continuous learning. Feel free to explore this showcase of my 24 | passion and expertise in action. 25 |

26 |
27 |
28 | 29 |
30 | {portfolioConfig.projects.map((val, indx) => { 31 | return ; 32 | })} 33 |
34 |
35 | ); 36 | }; 37 | 38 | export default projectsPage; 39 | -------------------------------------------------------------------------------- /src/app/skills/page.tsx: -------------------------------------------------------------------------------- 1 | import Heading from "@/components/Heading"; 2 | import SkillsFooter from "@/components/SkillsFotter"; 3 | import { Badge } from "@/components/ui/badge"; 4 | import { LightbulbIcon } from "lucide-react"; 5 | import FramerWrapper from "@/components/animation/FramerWrapper"; 6 | import { portfolioConfig } from "@/config/portfolio.config"; 7 | 8 | const skillPage = () => { 9 | return ( 10 | // SKILLS PAGE 11 |
12 | 13 | 14 | My Skills 15 | 16 |
17 | My Technical Experience/Skills. 18 | 19 |

20 | Currently i am a fresher and i have a solid understand of HTML5, 21 | CSS3, JS, TS and React, including responsive design principles. I 22 | specialize in building web applications and sites using Javascript, 23 | Typescript, React, Nextjs & Node. 24 |

25 |
26 | 27 |

28 | Programming Languages 29 |

30 |
31 | 32 |
33 |
34 | 35 |

36 | Framework/Libraries 37 |

38 |
39 | 40 |
41 |
42 | 43 |

44 | Tools & Technologies 45 |

46 |
47 | 48 |
49 |
50 |
51 |
52 | ); 53 | }; 54 | 55 | export default skillPage; 56 | -------------------------------------------------------------------------------- /src/components/Aboutfooter.tsx: -------------------------------------------------------------------------------- 1 | import { Circle, Dna, Globe2, Languages } from "lucide-react"; 2 | import { portfolioConfig } from "@/config/portfolio.config"; 3 | 4 | const Aboutfooter = () => { 5 | const items = [ 6 | { 7 | name: "Language", 8 | answer: portfolioConfig.about.personalInfo.language, 9 | icon: , 10 | }, 11 | { 12 | name: "Nationality", 13 | answer: portfolioConfig.about.personalInfo.nationality, 14 | icon: , 15 | }, 16 | { 17 | name: "Gender", 18 | answer: portfolioConfig.about.personalInfo.gender, 19 | icon: , 20 | }, 21 | ]; 22 | 23 | return ( 24 | <> 25 | {items.map((val, indx) => { 26 | return ( 27 |
28 |

29 | {val.icon} 30 | {val.name} 31 |

32 |
33 | {val.answer} 34 |
35 |
36 | ); 37 | })} 38 | 39 | ); 40 | }; 41 | 42 | export default Aboutfooter; 43 | -------------------------------------------------------------------------------- /src/components/ContactForm.tsx: -------------------------------------------------------------------------------- 1 | import { Input } from "@/components/ui/input"; 2 | import { Label } from "@/components/ui/label"; 3 | 4 | import { 5 | Card, 6 | CardContent, 7 | CardDescription, 8 | CardFooter, 9 | CardHeader, 10 | CardTitle, 11 | } from "@/components/ui/card"; 12 | import { Button } from "./ui/button"; 13 | import { SendEmail } from "./SendEmail"; 14 | 15 | const ContactForm = () => { 16 | return ( 17 | 18 |
{ 20 | "use server"; 21 | await SendEmail(FormData); 22 | }} 23 | > 24 | 25 | Send me a mail. 26 | 27 | Once form is submit you will be redirect to home page. 28 | 29 | 30 | 31 |
32 | 33 | 39 |
40 |
41 | 42 | 48 |
49 |
50 | 51 | 57 |
58 |
59 | 60 | 63 | 64 |
65 |
66 | ); 67 | }; 68 | 69 | export default ContactForm; 70 | -------------------------------------------------------------------------------- /src/components/DownLoadResumeBtn.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | import { Download } from 'lucide-react' 3 | import Link from 'next/link' 4 | import React from 'react' 5 | import { buttonVariants } from './ui/button' 6 | import HackerBtn from './animation/HackerBtn' 7 | 8 | function DownLoadResumeBtn() { 9 | return ( 10 |
11 | 12 | 13 |
14 | ) 15 | } 16 | 17 | export default DownLoadResumeBtn -------------------------------------------------------------------------------- /src/components/Heading.tsx: -------------------------------------------------------------------------------- 1 | import FramerWrapper from "./animation/FramerWrapper"; 2 | 3 | const Heading = ({ children }: { children: React.ReactNode }) => { 4 | // CUSTOM HEADING FOR ALL PAGE 5 | return ( 6 | 7 |

8 | {children} 9 |

10 |
11 | ); 12 | }; 13 | 14 | export default Heading; 15 | -------------------------------------------------------------------------------- /src/components/HeroImage.tsx: -------------------------------------------------------------------------------- 1 | import logo from "../../public/portfolioLogo.png"; 2 | import Image from "next/image" 3 | 4 | const HeroImage = () => { 5 | 6 | 7 | 8 | return( 9 | <> 10 | logo 18 | 19 | ) 20 | } 21 | export default HeroImage -------------------------------------------------------------------------------- /src/components/HeroTexts.tsx: -------------------------------------------------------------------------------- 1 | import TextRotator from "./TextRotator"; 2 | import { portfolioConfig } from "@/config/portfolio.config"; 3 | 4 | const HeroTexts = () => { 5 | // Get the name parts 6 | const nameParts = portfolioConfig.name.split(" "); 7 | const firstName = nameParts[0]; 8 | const middleName = nameParts.length > 2 ? nameParts[1] : ""; 9 | const lastName = nameParts.length > 2 ? nameParts[2] : nameParts[1]; 10 | 11 | return ( 12 | <> 13 |

My Name is

14 |

15 | {firstName} {middleName}
{lastName} . 16 |

17 | 18 | 19 | ); 20 | }; 21 | export default HeroTexts; 22 | -------------------------------------------------------------------------------- /src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { cn } from "@/lib/utils"; 3 | 4 | 5 | import { 6 | Briefcase, 7 | FolderGit2, 8 | GraduationCap, 9 | HomeIcon, 10 | LightbulbIcon, 11 | Mail, 12 | MoreHorizontal, 13 | 14 | User, 15 | } from 'lucide-react'; 16 | 17 | import { Dock, DockIcon, DockItem, DockLabel } from '@/components/animation/DockAnimation'; 18 | 19 | import Link from "next/link"; 20 | import { useEffect, useState } from "react"; 21 | import FramerWrapper from "./animation/FramerWrapper"; 22 | import { usePathname } from "next/navigation"; 23 | 24 | const Navbar = () => { 25 | 26 | const data = [ 27 | { 28 | title: 'Home', 29 | icon: ( 30 | 31 | ), 32 | href: '/', 33 | }, 34 | { 35 | title: 'About', 36 | icon: ( 37 | 38 | ), 39 | href: '/about', 40 | }, 41 | { 42 | title: 'Skills', 43 | icon: ( 44 | 45 | ), 46 | href: '/skills', 47 | }, 48 | { 49 | title: 'Education', 50 | icon: ( 51 | 52 | ), 53 | href: '/education', 54 | }, 55 | { 56 | title: 'Projects', 57 | icon: ( 58 | 59 | ), 60 | href: '/projects', 61 | }, 62 | 63 | { 64 | title: 'Contact us', 65 | icon: ( 66 | 67 | ), 68 | href: '/contact', 69 | }, 70 | { 71 | title: 'More', 72 | icon: ( 73 | 74 | ), 75 | href: '/more', 76 | }, 77 | ]; 78 | const [scrolling, setScrolling] = useState(false); 79 | const pathname = usePathname() 80 | 81 | useEffect(() => { 82 | const handleScroll = () => { 83 | if (window.scrollY > 0) { 84 | setScrolling(true); 85 | } else { 86 | setScrolling(false); 87 | } 88 | }; 89 | 90 | window.addEventListener('scroll', handleScroll); 91 | 92 | return () => { 93 | window.removeEventListener('scroll', handleScroll); 94 | }; 95 | }, []); 96 | 97 | 98 | return ( 99 | 100 |
101 | 102 | {data.map((item, idx) => ( 103 | 104 | 105 | 108 | {item.title} 109 | {item.icon} 110 | 111 | 112 | ))} 113 | 114 |
115 | ); 116 | }; 117 | 118 | export default Navbar; 119 | -------------------------------------------------------------------------------- /src/components/ProjectsCard.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import Link from "next/link"; 3 | import { buttonVariants } from "./ui/button"; 4 | import { 5 | Card, 6 | CardContent, 7 | CardFooter, 8 | CardHeader, 9 | CardTitle, 10 | } from "@/components/ui/card"; 11 | import FramerWrapper from "./animation/FramerWrapper"; 12 | import { ArrowUpRight } from "lucide-react"; 13 | 14 | interface ProjectCardProps { 15 | value: { 16 | title: string; 17 | description: string; 18 | tags: string[]; 19 | link: string; 20 | }; 21 | num: number; 22 | } 23 | 24 | const ProjectCards: React.FC = ({ value, num }) => { 25 | return ( 26 | 33 | 34 | 35 | {value.title} 36 | 37 | 38 | 39 |

{value.description}

40 | 41 |
42 | {value.tags.map((tag: string, index: number) => { 43 | const tagStyles = { 44 | 'Nextjs': 'bg-teal-100 text-teal-800', 45 | 'Freelancing': 'bg-yellow-100 text-yellow-800', 46 | 'Shadcn Ui': 'bg-blue-100 text-blue-800', 47 | 'Typescript': 'bg-red-100 text-red-800', 48 | 'MySQL': 'bg-orange-100 text-orange-800', 49 | 'Zustand': 'bg-purple-100 text-purple-800', 50 | 'Supabase': 'bg-emerald-100 text-emerald-800', 51 | 'Npx': 'bg-indigo-100 text-indigo-800', 52 | 'Library': 'bg-pink-100 text-pink-800', 53 | 'Zod': 'bg-cyan-100 text-cyan-800', 54 | 'React Hook Form': 'bg-violet-100 text-violet-800' 55 | }[tag] || 'bg-gray-100 text-gray-800'; 56 | 57 | return ( 58 | 62 | {tag} 63 | 64 | ); 65 | })} 66 |
67 |
68 | 69 | 70 | 82 | Visit Project 83 | 84 | 85 | 86 |
87 |
88 | ); 89 | }; 90 | 91 | export default ProjectCards; 92 | -------------------------------------------------------------------------------- /src/components/SendEmail.ts: -------------------------------------------------------------------------------- 1 | import { Resend } from "resend"; 2 | import {redirect} from 'next/navigation' 3 | 4 | 5 | // EMAIL SENDGING FUCTIONALITY 6 | // ADD RESEND_API_KEY IN YOUR .ENV FILE 7 | const resend = new Resend(process.env.RESEND_API_KEY); 8 | export const SendEmail = async (formdata: FormData) => { 9 | const message = formdata.get("message"); 10 | const name = formdata.get("name"); 11 | const SenderEmail = formdata.get("SenderEmail"); 12 | if (!message) { 13 | return { 14 | error: "Invalid message", 15 | }; 16 | } 17 | await resend.emails.send({ 18 | from: "Contact Form ", 19 | to: `mdtaqui.jhar@gmail.com`, 20 | subject: `${name} From Contact Form.`, 21 | reply_to: `${SenderEmail}`, 22 | text: `sender email: ${SenderEmail} 23 | ${message}`, 24 | }); 25 | 26 | return redirect('/') 27 | 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/SkillsFotter.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import React from "react"; 3 | 4 | interface MyComponentProps { 5 | items: Array<{ alt?: string; img?: any; name?: string; icon?: string }>; 6 | } 7 | 8 | const SkillsFooter: React.FC = ({ items }) => { 9 | return ( 10 | <> 11 | {items && 12 | items.map((item, index) => { 13 | return ( 14 | 15 |
19 | {item.name} 24 | 25 | {item.name} 26 | 27 |
28 | ); 29 | })} 30 | 31 | ); 32 | }; 33 | 34 | export default SkillsFooter; 35 | -------------------------------------------------------------------------------- /src/components/SocialLinks.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import { 3 | Facebook, 4 | Linkedin, 5 | Twitter, 6 | ExternalLink, 7 | Github, 8 | } from "lucide-react"; 9 | import { buttonVariants } from "./ui/button"; 10 | import Link from "next/link"; 11 | import FramerWrapper from "./animation/FramerWrapper"; 12 | import { portfolioConfig } from "@/config/portfolio.config"; 13 | 14 | const SocialLinks = () => { 15 | const links = [ 16 | { 17 | name: "Facebook", 18 | link: portfolioConfig.socialLinks.facebook, 19 | icon: , 20 | }, 21 | { 22 | name: "Twitter", 23 | link: portfolioConfig.socialLinks.twitter, 24 | icon: , 25 | }, 26 | { 27 | name: "Linkedin", 28 | link: portfolioConfig.socialLinks.linkedin, 29 | icon: , 30 | }, 31 | { 32 | name: "External", 33 | link: portfolioConfig.socialLinks.external, 34 | icon: , 35 | }, 36 | { 37 | name: "Github", 38 | link: portfolioConfig.socialLinks.github, 39 | icon: , 40 | }, 41 | ]; 42 | return ( 43 | <> 44 | {links.map((itm, indx) => { 45 | const timing = 0.55 + indx * 0.125; 46 | 47 | return ( 48 | 49 | 56 | {itm.icon} 57 | 58 | 59 | ); 60 | })} 61 | 62 | ); 63 | }; 64 | 65 | export default SocialLinks; 66 | -------------------------------------------------------------------------------- /src/components/TextRotator.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { portfolioConfig } from "@/config/portfolio.config"; 3 | 4 | function TextRotator() { 5 | return ( 6 |
7 |
8 | I am a {portfolioConfig.title} & 9 | 10 |
    11 | {portfolioConfig.skills.roles.map((role, index) => ( 12 |
  • 13 | {role} 14 |
  • 15 | ))} 16 |
17 |
18 |
19 |
20 | ); 21 | } 22 | 23 | export default TextRotator; 24 | -------------------------------------------------------------------------------- /src/components/animation/DockAnimation.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { 4 | motion, 5 | MotionValue, 6 | useMotionValue, 7 | useSpring, 8 | useTransform, 9 | type SpringOptions, 10 | AnimatePresence, 11 | } from 'framer-motion'; 12 | import { 13 | Children, 14 | cloneElement, 15 | createContext, 16 | useContext, 17 | useEffect, 18 | useMemo, 19 | useRef, 20 | useState, 21 | } from 'react'; 22 | import { cn } from '@/lib/utils'; 23 | 24 | const DOCK_HEIGHT = 128; 25 | const DEFAULT_MAGNIFICATION = 80; 26 | const DEFAULT_DISTANCE = 150; 27 | const DEFAULT_PANEL_HEIGHT = 64; 28 | 29 | type DockProps = { 30 | children: React.ReactNode; 31 | className?: string; 32 | distance?: number; 33 | panelHeight?: number; 34 | magnification?: number; 35 | spring?: SpringOptions; 36 | }; 37 | type DockItemProps = { 38 | className?: string; 39 | children: React.ReactNode; 40 | }; 41 | type DockLabelProps = { 42 | className?: string; 43 | children: React.ReactNode; 44 | }; 45 | type DockIconProps = { 46 | className?: string; 47 | children: React.ReactNode; 48 | }; 49 | 50 | type DocContextType = { 51 | mouseX: MotionValue; 52 | spring: SpringOptions; 53 | magnification: number; 54 | distance: number; 55 | }; 56 | type DockProviderProps = { 57 | children: React.ReactNode; 58 | value: DocContextType; 59 | }; 60 | 61 | const DockContext = createContext(undefined); 62 | 63 | function DockProvider({ children, value }: DockProviderProps) { 64 | return {children}; 65 | } 66 | 67 | function useDock() { 68 | const context = useContext(DockContext); 69 | if (!context) { 70 | throw new Error('useDock must be used within an DockProvider'); 71 | } 72 | return context; 73 | } 74 | 75 | function Dock({ 76 | children, 77 | className, 78 | spring = { mass: 0.1, stiffness: 150, damping: 12 }, 79 | magnification = DEFAULT_MAGNIFICATION, 80 | distance = DEFAULT_DISTANCE, 81 | panelHeight = DEFAULT_PANEL_HEIGHT, 82 | }: DockProps) { 83 | const mouseX = useMotionValue(Infinity); 84 | const isHovered = useMotionValue(0); 85 | 86 | const maxHeight = useMemo(() => { 87 | return Math.max(DOCK_HEIGHT, magnification + magnification / 2 + 4); 88 | }, [magnification]); 89 | 90 | const heightRow = useTransform(isHovered, [0, 1], [panelHeight, maxHeight]); 91 | const height = useSpring(heightRow, spring); 92 | 93 | return ( 94 | 101 | { 103 | isHovered.set(1); 104 | mouseX.set(pageX); 105 | }} 106 | onMouseLeave={() => { 107 | isHovered.set(0); 108 | mouseX.set(Infinity); 109 | }} 110 | className={cn( 111 | 'mx-auto flex w-fit gap-1.5 sm:gap-4 rounded-2xl bg-gray-50 px-4 dark:bg-neutral-900', 112 | className 113 | )} 114 | style={{ height: panelHeight }} 115 | role='toolbar' 116 | aria-label='Application dock' 117 | > 118 | 119 | {children} 120 | 121 | 122 | 123 | ); 124 | } 125 | 126 | function DockItem({ children, className }: DockItemProps) { 127 | const ref = useRef(null); 128 | 129 | const { distance, magnification, mouseX, spring } = useDock(); 130 | 131 | const isHovered = useMotionValue(0); 132 | 133 | const mouseDistance = useTransform(mouseX, (val) => { 134 | const domRect = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 }; 135 | return val - domRect.x - domRect.width / 2; 136 | }); 137 | 138 | const widthTransform = useTransform( 139 | mouseDistance, 140 | [-distance, 0, distance], 141 | [40, magnification, 40] 142 | ); 143 | 144 | const width = useSpring(widthTransform, spring); 145 | 146 | return ( 147 | isHovered.set(1)} 151 | onHoverEnd={() => isHovered.set(0)} 152 | onFocus={() => isHovered.set(1)} 153 | onBlur={() => isHovered.set(0)} 154 | className={cn( 155 | 'relative inline-flex items-center justify-center', 156 | className 157 | )} 158 | tabIndex={0} 159 | role='button' 160 | aria-haspopup='true' 161 | > 162 | {Children.map(children, (child) => 163 | cloneElement(child as React.ReactElement, { width, isHovered }) 164 | )} 165 | 166 | ); 167 | } 168 | 169 | function DockLabel({ children, className, ...rest }: DockLabelProps) { 170 | const restProps = rest as Record; 171 | const isHovered = restProps['isHovered'] as MotionValue; 172 | const [isVisible, setIsVisible] = useState(false); 173 | 174 | useEffect(() => { 175 | const unsubscribe = isHovered.on('change', (latest) => { 176 | setIsVisible(latest === 1); 177 | }); 178 | 179 | return () => unsubscribe(); 180 | }, [isHovered]); 181 | 182 | return ( 183 | 184 | {isVisible && ( 185 | 197 | {children} 198 | 199 | )} 200 | 201 | ); 202 | } 203 | 204 | function DockIcon({ children, className, ...rest }: DockIconProps) { 205 | const restProps = rest as Record; 206 | const width = restProps['width'] as MotionValue; 207 | 208 | const widthTransform = useTransform(width, (val) => val / 2); 209 | 210 | return ( 211 | 215 | {children} 216 | 217 | ); 218 | } 219 | 220 | export { Dock, DockIcon, DockItem, DockLabel }; 221 | -------------------------------------------------------------------------------- /src/components/animation/FramerWrapper.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { motion, AnimatePresence } from "framer-motion"; 4 | type FramerMotionProps = { 5 | children: React.ReactNode, 6 | className?:any, 7 | y?:number 8 | x?:number 9 | delay?:number 10 | duration?: number 11 | scale?:number 12 | } 13 | function FramerWrapper({children,delay = 0.25 ,y = 15, x = 0,duration = 0.20,scale = 0, className}:FramerMotionProps) { 14 | const [animateConfig, setAnimateConfig] = useState({ 15 | opacity:1, y:0, x:0 16 | }) 17 | return ( 18 | 19 | {children} 26 | 27 | ); 28 | } 29 | 30 | export default FramerWrapper; -------------------------------------------------------------------------------- /src/components/animation/GithubBtn.tsx: -------------------------------------------------------------------------------- 1 | import { Github } from "lucide-react"; 2 | import Link from "next/link"; 3 | 4 | const GithubBtn = () => { 5 | return ( 6 | 7 | 8 | Github 9 | 10 | ); 11 | }; 12 | 13 | export default GithubBtn; 14 | -------------------------------------------------------------------------------- /src/components/animation/HackerBtn.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { useState, useEffect } from 'react'; 3 | import { Download } from 'lucide-react'; 4 | import { Button } from '../ui/button'; 5 | 6 | const HackerBtn = ({ label }: { label: string }) => { 7 | const [displayText, setDisplayText] = useState(label); 8 | const charset = "abcdefghijklmnopqrstuvwxyz"; 9 | 10 | const randomChars = (length: number) => { 11 | return Array.from( 12 | { length }, 13 | () => charset[Math.floor(Math.random() * charset.length)] 14 | ).join(""); 15 | }; 16 | 17 | const scramble = async (input: string) => { 18 | let prefix = ""; 19 | for (let index = 0; index < input.length; index++) { 20 | await new Promise((resolve) => setTimeout(resolve, 50)); 21 | prefix += input.charAt(index); 22 | setDisplayText(prefix + randomChars(input.length - prefix.length)); 23 | } 24 | }; 25 | 26 | const startScrambling = () => { 27 | scramble(label); 28 | setTimeout(() => console.log("Submitted"), label.length * 50); 29 | }; 30 | 31 | useEffect(() => { 32 | setDisplayText(label); 33 | }, [label]); 34 | 35 | return ( 36 | 40 | ); 41 | }; 42 | 43 | export default HackerBtn; 44 | -------------------------------------------------------------------------------- /src/components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "@/lib/utils" 5 | import FramerWrapper from "../animation/FramerWrapper" 6 | 7 | const badgeVariants = cva( 8 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", 14 | secondary: 15 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 16 | destructive: 17 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", 18 | outline: "text-foreground", 19 | }, 20 | }, 21 | defaultVariants: { 22 | variant: "default", 23 | }, 24 | } 25 | ) 26 | 27 | export interface BadgeProps 28 | extends React.HTMLAttributes, 29 | VariantProps {} 30 | 31 | function Badge({ className, variant, ...props }: BadgeProps) { 32 | return ( 33 | 34 | 35 |
36 | 37 | ) 38 | } 39 | 40 | export { Badge, badgeVariants } 41 | -------------------------------------------------------------------------------- /src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | import { cva, VariantProps } from 'class-variance-authority' 3 | import { Loader2 } from 'lucide-react' 4 | import * as React from 'react' 5 | 6 | const buttonVariants = cva( 7 | 'active:scale-95 inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:opacity-50 dark:focus:ring-slate-400 disabled:pointer-events-none dark:focus:ring-offset-slate-900', 8 | { 9 | variants: { 10 | variant: { 11 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 12 | destructive: 13 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 14 | outline: 15 | 'border border-[#000] bg-transparent hover:bg-accent hover:text-accent-foreground', 16 | custom: 17 | ' bg-[#020817] text-white hover:bg-[#020817d6] hover:shadow-lg', 18 | subtle: 19 | 'border border-input bg-background hover:bg-[#6aa2e6] hover:text-white', 20 | ghost: 21 | 'bg-transparent hover:bg-zinc-100 text-zinc-800 data-[state=open]:bg-transparent data-[state=open]:bg-transparent', 22 | link: 'bg-transparent dark:bg-transparent underline-offset-4 hover:underline text-slate-900 dark:text-slate-100 hover:bg-transparent dark:hover:bg-transparent', 23 | }, 24 | size: { 25 | default: 'h-10 py-2 px-4', 26 | sm: 'h-9 px-2 rounded-md', 27 | xs: 'h-8 px-1.5 rounded-sm', 28 | lg: 'h-11 px-8 rounded-md', 29 | icon: "h-10 w-10", 30 | notch:"text-2xl px-2" 31 | }, 32 | }, 33 | defaultVariants: { 34 | variant: 'default', 35 | size: 'default', 36 | }, 37 | } 38 | ) 39 | 40 | export interface ButtonProps 41 | extends React.ButtonHTMLAttributes, 42 | VariantProps { 43 | isLoading?: boolean 44 | } 45 | 46 | const Button = React.forwardRef( 47 | ({ className, children, variant, isLoading, size, ...props }, ref) => { 48 | return ( 49 | 57 | ) 58 | } 59 | ) 60 | Button.displayName = 'Button' 61 | 62 | export { Button, buttonVariants } -------------------------------------------------------------------------------- /src/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Card = React.forwardRef< 6 | HTMLDivElement, 7 | React.HTMLAttributes 8 | >(({ className, ...props }, ref) => ( 9 |
17 | )) 18 | Card.displayName = "Card" 19 | 20 | const CardHeader = React.forwardRef< 21 | HTMLDivElement, 22 | React.HTMLAttributes 23 | >(({ className, ...props }, ref) => ( 24 |
29 | )) 30 | CardHeader.displayName = "CardHeader" 31 | 32 | const CardTitle = React.forwardRef< 33 | HTMLParagraphElement, 34 | React.HTMLAttributes 35 | >(({ className, ...props }, ref) => ( 36 |

44 | )) 45 | CardTitle.displayName = "CardTitle" 46 | 47 | const CardDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 |

56 | )) 57 | CardDescription.displayName = "CardDescription" 58 | 59 | const CardContent = React.forwardRef< 60 | HTMLDivElement, 61 | React.HTMLAttributes 62 | >(({ className, ...props }, ref) => ( 63 |

64 | )) 65 | CardContent.displayName = "CardContent" 66 | 67 | const CardFooter = React.forwardRef< 68 | HTMLDivElement, 69 | React.HTMLAttributes 70 | >(({ className, ...props }, ref) => ( 71 |
76 | )) 77 | CardFooter.displayName = "CardFooter" 78 | 79 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 80 | -------------------------------------------------------------------------------- /src/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | } 22 | ) 23 | Input.displayName = "Input" 24 | 25 | export { Input } 26 | -------------------------------------------------------------------------------- /src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /src/components/ui/tooltip.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as TooltipPrimitive from "@radix-ui/react-tooltip" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const TooltipProvider = TooltipPrimitive.Provider 9 | 10 | const Tooltip = TooltipPrimitive.Root 11 | 12 | const TooltipTrigger = TooltipPrimitive.Trigger 13 | 14 | const TooltipContent = React.forwardRef< 15 | React.ElementRef, 16 | React.ComponentPropsWithoutRef 17 | >(({ className, sideOffset = 4, ...props }, ref) => ( 18 | 27 | )) 28 | TooltipContent.displayName = TooltipPrimitive.Content.displayName 29 | 30 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } 31 | -------------------------------------------------------------------------------- /src/config/portfolio.config.ts: -------------------------------------------------------------------------------- 1 | export const portfolioConfig = { 2 | // Basic Information 3 | name: "Md Taqui Imam", 4 | title: "Software Engineer", 5 | description: "I am a Passionate Software Developer", 6 | location: "Ramgarh cantt, Jharkhand, India", 7 | 8 | // Contact Information 9 | email: "taquiimam@example.com", // Replace with actual email if available 10 | 11 | // Social Media Links 12 | socialLinks: { 13 | facebook: "https://www.facebook.com/shahina.khatun.1044", 14 | twitter: "https://twitter.com/Taquiimam14", 15 | linkedin: "https://www.linkedin.com/in/taqui-imam", 16 | external: "https://tinyurl.com/MdTaquiImam", 17 | github: "https://github.com/taqui-786", // Assuming this is the GitHub link 18 | }, 19 | 20 | // SEO Information 21 | seo: { 22 | ogImage: "https://mdtaquiimam.vercel.app/og-image.png", 23 | url: "https://mdtaquiimam.vercel.app", 24 | twitterHandle: "@Taquiimam14", 25 | keywords: [ 26 | "md", 27 | "taqui", 28 | "imam", 29 | "Md", 30 | "MD", 31 | "TAQUI", 32 | "Taqui", 33 | "Imam", 34 | "Imam", 35 | "Md Taqui Imam", 36 | "md taqui imam", 37 | "mdtaqui", 38 | "mdtaquiimam", 39 | "taqui imam", 40 | "Taqui Imam", 41 | "Taquiimam", 42 | "portfolio", 43 | "web developer", 44 | "web", 45 | "web dev", 46 | "developer", 47 | "PROGRAMMER ", 48 | "programmer ", 49 | "MD TAQUI IMAM ", 50 | "website", 51 | "@Taquiimam", 52 | "Taquiimam", 53 | "taqui developer", 54 | ], 55 | authors: [ 56 | { 57 | name: "Taqui Imam", 58 | url: "https://github.com/taqui-786", 59 | }, 60 | ], 61 | }, 62 | 63 | // About Information 64 | about: { 65 | bio: "I am a Full Stack Web Developer from Ramgarh cantt, Jharkhand, India. I'm passionate about crafting web projects and contributing to open-source communities. I specialize in modern JavaScript frameworks and responsive CSS design, focusing on creating pixel-perfect, user-friendly interfaces. With strong attention to detail and efficient delivery, I build seamless web experiences that combine functionality with elegant design.", 66 | hobbies: [ 67 | "Coding", 68 | "Playing Games", 69 | "Watching Anime", 70 | "Tech Blog Writing", 71 | "Creating Cool Projects", 72 | ], 73 | personalInfo: { 74 | language: "English UK", 75 | nationality: "India", 76 | gender: "Male", 77 | }, 78 | }, 79 | 80 | // Skills and Roles 81 | skills: { 82 | roles: [ 83 | "Freelancer", 84 | "Blogger", 85 | "Gamer", 86 | "Creator", 87 | "Student", 88 | "Contributer", 89 | ], 90 | // Technical Skills 91 | programmingLanguages: [ 92 | { 93 | name: "HTML5", 94 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/html5/html5-original.svg", 95 | }, 96 | { 97 | name: "CSS3", 98 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/css3/css3-original.svg", 99 | }, 100 | { 101 | name: "JavaScript", 102 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/javascript/javascript-original.svg", 103 | }, 104 | { 105 | name: "TypeScript", 106 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/typescript/typescript-original.svg", 107 | }, 108 | { 109 | name: "C++", 110 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/cplusplus/cplusplus-original.svg", 111 | }, 112 | { 113 | name: "Python", 114 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/python/python-original.svg", 115 | }, 116 | { 117 | name: "Java", 118 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/java/java-original.svg", 119 | }, 120 | ], 121 | frameworks: [ 122 | { 123 | name: "React", 124 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/react/react-original.svg", 125 | }, 126 | { 127 | name: "Next.js", 128 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/nextjs/nextjs-original.svg", 129 | }, 130 | { 131 | name: "Vue.js", 132 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/vuejs/vuejs-original.svg", 133 | }, 134 | { 135 | name: "Svelte", 136 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/svelte/svelte-original.svg", 137 | }, 138 | { 139 | name: "Tailwind CSS", 140 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/tailwindcss/tailwindcss-original.svg", 141 | }, 142 | { 143 | name: "Bootstrap", 144 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/bootstrap/bootstrap-original.svg", 145 | }, 146 | { 147 | name: "Material UI", 148 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/materialui/materialui-original.svg", 149 | }, 150 | ], 151 | tools: [ 152 | { 153 | name: "Git", 154 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/git/git-original.svg", 155 | }, 156 | { 157 | name: "GitHub", 158 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/github/github-original.svg", 159 | }, 160 | { 161 | name: "VS Code", 162 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/vscode/vscode-original.svg", 163 | }, 164 | { 165 | name: "Docker", 166 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/docker/docker-original.svg", 167 | }, 168 | { 169 | name: "Firebase", 170 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/firebase/firebase-plain.svg", 171 | }, 172 | { 173 | name: "MongoDB", 174 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/mongodb/mongodb-original.svg", 175 | }, 176 | { 177 | name: "PostgreSQL", 178 | icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/postgresql/postgresql-original.svg", 179 | }, 180 | ], 181 | }, 182 | 183 | // Education Information 184 | education: [ 185 | { 186 | degree: "Bachelor of Computer Application", 187 | institution: "Ranchi University Jharkhand", 188 | location: "Doranda College Ranchi", 189 | period: "July 2023 - 2026", 190 | description: 191 | "I am currently Studying Bachelor of Computer Application form Doranda College Ranchi a Goverment College of Ranchi. The program has provided me with a well-rounded education, covering both theoretical foundations and practical applications of computer science.", 192 | }, 193 | ], 194 | 195 | // Projects Information 196 | projects: [ 197 | { 198 | title: "WePost- A modern, minimalistic social platform.", 199 | description: 200 | "WePost is a modern, minimalistic social platform for sharing posts, like, follow, and engaging in comments etc.", 201 | tags: ["Tanstack-Query", "PostgreSQL", "Shadcn Ui", "Nextjs"], 202 | link: "https://we-post-dev.vercel.app", 203 | }, 204 | { 205 | title: "Devzone- A community chat app for devs", 206 | description: 207 | "DevZone is the ultimate chat platform for developers to connect, collaborate, and code together. Join the conversation and level up your coding journey.", 208 | tags: ["Zustand", "Supabase", "Shadcn Ui", "Nextjs"], 209 | link: "https://devzone-ti.vercel.app/", 210 | }, 211 | { 212 | title: "itZmyLink- One Page many Links", 213 | description: 214 | "itZmyLink is a simple platform where user can create a personalized page to showcase all your social media profiles in one place. ", 215 | tags: ["Nextjs", "Typescript", "Shadcn Ui"], 216 | link: "https://github.com/taqui-786/itZmyLink", 217 | }, 218 | { 219 | title: "GitEstimate- Github estimate worth generator", 220 | description: 221 | "GitEstimate is a simple fun tool where user can generate their github estimate worth card just by entering their github username. ", 222 | tags: ["Nextjs", "Typescript", "Shadcn Ui"], 223 | link: "https://github.com/taqui-786/GitEstimate", 224 | }, 225 | { 226 | title: "Mixcn-ui- Reusable components for Nextjs", 227 | description: 228 | "This is Nextjs app with a Collection of Nextjs Components - (Currently under Devlelopment) ", 229 | tags: ["Nextjs", "Shadcnui", "Npx", "Library"], 230 | link: "https://mixcn-ui.vercel.app", 231 | }, 232 | { 233 | title: "Rupeespot- All deals Product in one place", 234 | description: 235 | "This is a free tool to check price history charts for millions of products for popular Indian stores such as Amazon and Flipkart. ", 236 | tags: ["Nextjs", "Freelancing", "MySQL"], 237 | link: "https://rupeespot.com/", 238 | }, 239 | { 240 | title: "Formcraft- Build Type-Safe Forms with Zero Effort", 241 | description: 242 | "Create production-ready forms with Zod validation, React Hook Form, and TypeScript. Design, customize, and deploy in minutes.", 243 | tags: ["Nextjs", "Shadcnui", "Zod", "React Hook Form "], 244 | link: "https://formcraft-ti.vercel.app/", 245 | }, 246 | { 247 | title: "KryptoKapital- Investing in Cryptocurreny", 248 | description: 249 | "This is a platform for learning about cryptocurrency with many tools and festures. It is very big project. ", 250 | tags: ["Nextjs", "Freelancing", "Supabase"], 251 | link: "https://pro.kryptokapital.info/", 252 | }, 253 | { 254 | title: "FriendZ - A social media Platform", 255 | description: 256 | "FriendZ is a social media app made with modern tech stacks such as redis, Authjs etc. A user can Create, delete, like, comment Post. ", 257 | tags: ["Redis", "Authjs", "Typescript", "Nextjs"], 258 | link: "https://github.com/taqui-786/project-friendz", 259 | }, 260 | { 261 | title: "ChatApp- Simple instagram clone", 262 | description: 263 | "ChatApp is similar to instagram, you can create, edit, delete, like,comment, post and Follow, unfollow users", 264 | tags: ["Reactjs", "Javascript"], 265 | link: "https://github.com/taqui-786/chatapp-api", 266 | }, 267 | { 268 | title: "Devletter - A Newsletter for devs", 269 | description: 270 | "Devletter ia a newsletter subscribing single page app made with Nextjs and Tailwindcss.", 271 | tags: ["Nextjs", "Tailwindcss"], 272 | link: "https://github.com/taqui-786/Devletter", 273 | }, 274 | { 275 | title: "CrouMaker - A Crousal Maker App", 276 | description: 277 | "Crousal Maker is a tool with in-built crousals templates edit and download it in any format.", 278 | tags: ["Nextjs", "jsPDF", "html2canvas", "Shadcn Ui"], 279 | link: "https://github.com/taqui-786/crousal-maker", 280 | }, 281 | ], 282 | 283 | // More Links Information 284 | moreLinks: [ 285 | { 286 | title: "Dev.to", 287 | description: 288 | "I write blogs on web development, trending tech stacks or javascript guide or tips in Dev.to ", 289 | link: "https://dev.to/random_ti", 290 | }, 291 | { 292 | title: "Hashnode", 293 | description: 294 | "I write blogs on web development, trending tech stacks or javascript guide or tips in Hashnode", 295 | link: "https://mdtaquiimam.hashnode.dev/", 296 | }, 297 | { 298 | title: "Medium", 299 | description: 300 | "I write blogs on web development, trending tech stacks or javascript guide or tips in Medium", 301 | link: "https://medium.com/@mdtaqui.jhar", 302 | }, 303 | { 304 | title: "Daily.Dev", 305 | description: 306 | "I am also the member of Daily Dev squads and i also upload post on some squads.", 307 | link: "https://app.daily.dev/taqui_786", 308 | }, 309 | { 310 | title: "Gumroad", 311 | description: 312 | "I also sell digital products on gumroad like Notion Templates and web projects etc.", 313 | link: "https://mdtaquijhar.gumroad.com/", 314 | }, 315 | { 316 | title: "Buy Me a coffee", 317 | description: 318 | "Supports my content quality, new topics, and project creation.", 319 | link: "https://www.buymeacoffee.com/taquidevloper", 320 | }, 321 | ], 322 | 323 | // API Keys (should be in .env but referenced here) 324 | apiKeys: { 325 | resendApiKey: "YOUR_RESEND_API_KEY", // This should be loaded from environment variables in a real app 326 | }, 327 | }; 328 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: ["class"], 4 | content: [ 5 | './pages/**/*.{ts,tsx}', 6 | './components/**/*.{ts,tsx}', 7 | './app/**/*.{ts,tsx}', 8 | './src/**/*.{ts,tsx}', 9 | ], 10 | theme: { 11 | screens: { 12 | sm: '480px', 13 | md: '720px', 14 | lg: '976px', 15 | xl: '1440px', 16 | }, 17 | container: { 18 | center: true, 19 | padding: "2rem", 20 | screens: { 21 | "2xl": "1400px", 22 | }, 23 | 24 | }, 25 | extend: { 26 | fontFamily:{ 27 | poppins: ['var(--font-poppins)'], 28 | rubik: ['var(--font-rubik)'] 29 | }, 30 | colors: { 31 | border: "hsl(var(--border))", 32 | input: "hsl(var(--input))", 33 | ring: "hsl(var(--ring))", 34 | background: "hsl(var(--background))", 35 | foreground: "hsl(var(--foreground))", 36 | primary: { 37 | DEFAULT: "hsl(var(--primary))", 38 | foreground: "hsl(var(--primary-foreground))", 39 | sky: "hsl(var(--primary-sky))", 40 | }, 41 | secondary: { 42 | DEFAULT: "hsl(var(--secondary))", 43 | foreground: "hsl(var(--secondary-foreground))", 44 | }, 45 | destructive: { 46 | DEFAULT: "hsl(var(--destructive))", 47 | foreground: "hsl(var(--destructive-foreground))", 48 | }, 49 | muted: { 50 | DEFAULT: "hsl(var(--muted))", 51 | foreground: "hsl(var(--muted-foreground))", 52 | }, 53 | accent: { 54 | DEFAULT: "hsl(var(--accent))", 55 | foreground: "hsl(var(--accent-foreground))", 56 | }, 57 | popover: { 58 | DEFAULT: "hsl(var(--popover))", 59 | foreground: "hsl(var(--popover-foreground))", 60 | }, 61 | card: { 62 | DEFAULT: "hsl(var(--card))", 63 | foreground: "hsl(var(--card-foreground))", 64 | }, 65 | }, 66 | borderRadius: { 67 | lg: "var(--radius)", 68 | md: "calc(var(--radius) - 2px)", 69 | sm: "calc(var(--radius) - 4px)", 70 | }, 71 | keyframes: { 72 | "accordion-down": { 73 | from: { height: 0 }, 74 | to: { height: "var(--radix-accordion-content-height)" }, 75 | }, 76 | "accordion-up": { 77 | from: { height: "var(--radix-accordion-content-height)" }, 78 | to: { height: 0 }, 79 | }, 80 | }, 81 | animation: { 82 | "accordion-down": "accordion-down 0.2s ease-out", 83 | "accordion-up": "accordion-up 0.2s ease-out", 84 | }, 85 | }, 86 | }, 87 | plugins: [require("tailwindcss-animate")], 88 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | --------------------------------------------------------------------------------