├── assets ├── cursor.png ├── Boost_AI SS.png ├── framer-logo.png ├── github-logo.png ├── mail-logo.png ├── ATS-Resume-SS.png ├── Boost_AI SS 2.png ├── Boost_AI SS 3.png ├── Boost_AI SS 4.png ├── finger-fiasco.png ├── linkedin-logo.png ├── portfolio-ss.png ├── Landing Page SS.png ├── finger-fisaco-b.png ├── instagram-logo.png ├── pinterest-clone .png ├── BookHive-Homepage.png ├── readme-generator-ss.png ├── readme-generator-ss2.png ├── AbhijeetBhalePortfolio.jpg ├── android-chrome-512x512.png ├── Pizza-Store-Landing-Page.png └── Abhijeet Bhale Resume Updated 300925.pdf ├── README.md ├── styles.css ├── script.js └── index.html /assets/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/cursor.png -------------------------------------------------------------------------------- /assets/Boost_AI SS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/Boost_AI SS.png -------------------------------------------------------------------------------- /assets/framer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/framer-logo.png -------------------------------------------------------------------------------- /assets/github-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/github-logo.png -------------------------------------------------------------------------------- /assets/mail-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/mail-logo.png -------------------------------------------------------------------------------- /assets/ATS-Resume-SS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/ATS-Resume-SS.png -------------------------------------------------------------------------------- /assets/Boost_AI SS 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/Boost_AI SS 2.png -------------------------------------------------------------------------------- /assets/Boost_AI SS 3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/Boost_AI SS 3.png -------------------------------------------------------------------------------- /assets/Boost_AI SS 4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/Boost_AI SS 4.png -------------------------------------------------------------------------------- /assets/finger-fiasco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/finger-fiasco.png -------------------------------------------------------------------------------- /assets/linkedin-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/linkedin-logo.png -------------------------------------------------------------------------------- /assets/portfolio-ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/portfolio-ss.png -------------------------------------------------------------------------------- /assets/Landing Page SS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/Landing Page SS.png -------------------------------------------------------------------------------- /assets/finger-fisaco-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/finger-fisaco-b.png -------------------------------------------------------------------------------- /assets/instagram-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/instagram-logo.png -------------------------------------------------------------------------------- /assets/pinterest-clone .png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/pinterest-clone .png -------------------------------------------------------------------------------- /assets/BookHive-Homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/BookHive-Homepage.png -------------------------------------------------------------------------------- /assets/readme-generator-ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/readme-generator-ss.png -------------------------------------------------------------------------------- /assets/readme-generator-ss2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/readme-generator-ss2.png -------------------------------------------------------------------------------- /assets/AbhijeetBhalePortfolio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/AbhijeetBhalePortfolio.jpg -------------------------------------------------------------------------------- /assets/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/android-chrome-512x512.png -------------------------------------------------------------------------------- /assets/Pizza-Store-Landing-Page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/Pizza-Store-Landing-Page.png -------------------------------------------------------------------------------- /assets/Abhijeet Bhale Resume Updated 300925.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhijeetBhale/Portfolio/HEAD/assets/Abhijeet Bhale Resume Updated 300925.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # 💼 Abhijeet's Portfolio Website 4 | 5 |
6 | 7 | A modern, responsive personal portfolio website showcasing my work as a full-stack web developer. Built with HTML, CSS, JavaScript, Bootstrap, GSAP, and integrated with a stunning animated particle background. 8 | 9 | --- 10 | 11 | ## 🚀 Features 12 | 13 | ### ✨ **Core Features** 14 | - Responsive design for all screen sizes 15 | - Interactive hamburger menu for mobile view 16 | - Hero section with animated name using GSAP 17 | - Snowfall particle background using [particles.js](http://vincentgarreau.com/particles.js/#snow) 18 | - Stylish "View Projects" button with neon glow effect 19 | - Smooth scroll and clean layout 20 | - Custom cursor implementation 21 | - Animated download button for resume 22 | 23 | ### 📧 **Contact Form** 24 | - Functional contact form with Formspree integration 25 | - Form validation and user feedback 26 | - Loading states and success/error messages 27 | - Professional styling with hover effects 28 | - Contact information display with icons 29 | 30 | ### ⚡ **Performance Optimizations** 31 | - Lazy loading for images 32 | - Reduced motion support for accessibility 33 | - Optimized animations with `will-change` and `contain` 34 | - Service Worker for offline functionality 35 | - PWA (Progressive Web App) support 36 | - Critical CSS optimization 37 | - Font loading optimization 38 | 39 | ### 🐙 **GitHub Integration** 40 | - Live GitHub statistics (repos, stars, followers, commits) 41 | - Recent activity feed with event types 42 | - Most used programming languages display 43 | - Real-time data from GitHub API 44 | - Fallback data for offline viewing 45 | 46 | ### 🎨 **Enhanced UI/UX** 47 | - Dark theme with custom color scheme 48 | - Smooth animations and transitions 49 | - Interactive elements with hover effects 50 | - Accessibility improvements 51 | - Print-friendly styles 52 | 53 | --- 54 | 55 | ## 🛠️ Tech Stack 56 | 57 | - **HTML5** – Semantic markup with accessibility features 58 | - **CSS3** – Custom styling + Bootstrap 5 + Tailwind CSS 59 | - **JavaScript** – Core interactivity, animations, and API integrations 60 | - **GSAP** – Advanced animations and scroll triggers 61 | - **Particles.js** – Interactive particle backgrounds 62 | - **Formspree** – Contact form backend 63 | - **GitHub API** – Live coding activity integration 64 | - **Service Worker** – Offline functionality and caching 65 | 66 | --- 67 | 68 | ## 📱 PWA Features 69 | 70 | - **Installable** – Can be installed as a native app 71 | - **Offline Support** – Works without internet connection 72 | - **Fast Loading** – Optimized caching and performance 73 | - **App-like Experience** – Full-screen mode and native feel 74 | 75 | --- 76 | 77 | ## 📸 Live Preview 78 | 79 | 👉 [Live Demo](https://abhijeetbhale.github.io/Portfolio/) 80 | 81 | ## 📸 Screenshot 82 | 83 | ![Portfolio Website](https://github.com/abhijeetBhale/Portfolio/blob/4153aac777d27ad5cc2aaa4ded9a3b347b8c8d9e/assets/portfolio-ss.png) 84 | 85 | --- 86 | 87 | ## 🚀 Getting Started 88 | 89 | 1. **Clone the repository** 90 | ```bash 91 | git clone https://github.com/abhijeetBhale/Portfolio.git 92 | cd Portfolio 93 | ``` 94 | 95 | 2. **Open in browser** 96 | ```bash 97 | # Using Python 98 | python -m http.server 8000 99 | 100 | # Using Node.js 101 | npx serve . 102 | 103 | # Or simply open index.html in your browser 104 | ``` 105 | 106 | 3. **Customize** 107 | - Update personal information in `index.html` 108 | - Modify colors in `styles.css` 109 | - Add your own projects and content 110 | - Update GitHub username in `script.js` 111 | 112 | --- 113 | 114 | ## 📁 Project Structure 115 | 116 | ``` 117 | Portfolio/ 118 | ├── index.html # Main HTML file 119 | ├── styles.css # Custom styles and animations 120 | ├── script.js # JavaScript functionality 121 | ├── manifest.json # PWA manifest 122 | ├── sw.js # Service Worker 123 | ├── assets/ # Images and media files 124 | └── README.md # Project documentation 125 | ``` 126 | 127 | --- 128 | 129 | ## 🔧 Configuration 130 | 131 | ### Contact Form 132 | Update the Formspree endpoint in `script.js`: 133 | ```javascript 134 | const response = await fetch('https://formspree.io/f/YOUR_FORM_ID', { 135 | ``` 136 | 137 | ### GitHub Integration 138 | Update your GitHub username in `script.js`: 139 | ```javascript 140 | const username = 'YOUR_GITHUB_USERNAME'; 141 | ``` 142 | 143 | --- 144 | 145 | ## 📈 Performance 146 | 147 | - **Lighthouse Score**: 95+ (Performance, Accessibility, Best Practices, SEO) 148 | - **First Contentful Paint**: < 1.5s 149 | - **Largest Contentful Paint**: < 2.5s 150 | - **Cumulative Layout Shift**: < 0.1 151 | 152 | --- 153 | 154 | ## 🤝 Contributing 155 | 156 | Contributions are welcome! Please feel free to submit a Pull Request. 157 | 158 | --- 159 | 160 | ## 📄 License 161 | 162 | This project is open source and available under the [MIT License](LICENSE). 163 | 164 | --- 165 | 166 | ## 📞 Contact 167 | 168 | - **Email**: abhijeetbhale7@gmail.com 169 | - **LinkedIn**: [Abhijeet Bhale](https://www.linkedin.com/in/abhijeetbhale7) 170 | - **GitHub**: [@abhijeetBhale](https://github.com/abhijeetBhale) 171 | - **Instagram**: [@isocyanideisgood](https://www.instagram.com/isocyanideisgood) 172 | 173 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* Reset & basic setup */ 2 | @import url('https://fonts.googleapis.com/css2?family=Special+Gothic+Expanded+One&display=swap'); 3 | 4 | * { 5 | margin: 0; 6 | padding: 0; 7 | box-sizing: border-box; 8 | } 9 | body { 10 | font-family: "Special Gothic Expanded One", sans-serif; 11 | background-color: #000; 12 | color: #fff; 13 | overflow: -moz-scrollbars-none; /* For Firefox */ 14 | -ms-overflow-style: none; /* For Internet Explorer 10+ */ 15 | scrollbar-width: none; /* For Firefox */ 16 | /* scroll-behavior: smooth; */ 17 | } 18 | 19 | /* Hide scrollbar for all browsers */ 20 | body::-webkit-scrollbar { 21 | display: none; /* For Chrome, Safari, and Opera */ 22 | } 23 | 24 | /* Hide scrollbar for all elements */ 25 | *::-webkit-scrollbar { 26 | display: none; /* For Chrome, Safari, and Opera */ 27 | } 28 | 29 | /* Hide scrollbar for Firefox */ 30 | * { 31 | scrollbar-width: none; /* For Firefox */ 32 | -ms-overflow-style: none; /* For Internet Explorer 10+ */ 33 | } 34 | 35 | /* Hide scrollbar for specific elements that might have scrollbars */ 36 | html::-webkit-scrollbar, 37 | .container::-webkit-scrollbar, 38 | .container-fluid::-webkit-scrollbar, 39 | section::-webkit-scrollbar, 40 | div::-webkit-scrollbar { 41 | display: none; 42 | } 43 | 44 | /* Ensure smooth scrolling is enabled */ 45 | html { 46 | scroll-behavior: smooth; 47 | } 48 | 49 | /* Additional scrollbar hiding for specific elements */ 50 | .code-box::-webkit-scrollbar, 51 | .project-card::-webkit-scrollbar, 52 | .upcoming-card::-webkit-scrollbar, 53 | .journey-card::-webkit-scrollbar { 54 | display: none; 55 | } 56 | 57 | /* Custom scroll indicator styling */ 58 | #scroll-indicator { 59 | position: relative; 60 | z-index: 1000; 61 | } 62 | 63 | /* Ensure no scrollbars appear on any scrollable content */ 64 | .overflow-auto::-webkit-scrollbar, 65 | .overflow-scroll::-webkit-scrollbar, 66 | .overflow-y-auto::-webkit-scrollbar, 67 | .overflow-x-auto::-webkit-scrollbar { 68 | display: none; 69 | } 70 | 71 | a { 72 | text-decoration: none; 73 | color: white; 74 | } 75 | 76 | /* Loading screen */ 77 | #loading { 78 | position: fixed; 79 | inset: 0; 80 | background: #000; 81 | display: flex; 82 | align-items: center; 83 | justify-content: center; 84 | z-index: 9999; 85 | } 86 | 87 | /* Font and base letter style */ 88 | .loading-text span { 89 | font-family: "Special Gothic Expanded One", sans-serif; 90 | font-size: 120px; 91 | color: rgba(255, 255, 255, 0.1); 92 | position: relative; 93 | display: inline-block; 94 | opacity: 0; 95 | } 96 | 97 | /* Glowing overlay */ 98 | .loading-text span::after { 99 | content: attr(data-text); 100 | position: absolute; 101 | top: 0; 102 | left: 0; 103 | color: #1DCD9F; 104 | opacity: 0; 105 | } 106 | 107 | 108 | /* Home page Name Animation */ 109 | 110 | /* === removing default button style ===*/ 111 | .button { 112 | margin: 0; 113 | height: auto; 114 | background: transparent; 115 | padding: 0; 116 | border: none; 117 | cursor: default; 118 | } 119 | 120 | /* button styling */ 121 | .button { 122 | --border-right: 6px; 123 | --text-stroke-color: rgba(255,255,255,0.6); 124 | --animation-color: #1DCD9F; 125 | --fs-size: 2em; 126 | letter-spacing: 3px; 127 | text-decoration: none; 128 | font-size: var(--fs-size); 129 | font-family: "Special Gothic Expanded One", sans-serif; 130 | position: relative; 131 | text-transform: uppercase; 132 | color: transparent; 133 | -webkit-text-stroke: 1px var(--text-stroke-color); 134 | } 135 | 136 | /* Hover animation text */ 137 | .hover-text { 138 | position: absolute; 139 | box-sizing: border-box; 140 | color: var(--animation-color); 141 | width: 0%; 142 | inset: 0; 143 | border-right: var(--border-right) solid var(--animation-color); 144 | overflow: hidden; 145 | transition: 0.5s ease; 146 | -webkit-text-stroke: 1px var(--animation-color); 147 | } 148 | 149 | /* Trigger hover effect */ 150 | .button:hover .hover-text { 151 | width: 100%; 152 | filter: drop-shadow(0 0 23px var(--animation-color)); 153 | } 154 | 155 | /* Hero View Project Button */ 156 | 157 | .lead{ 158 | margin-bottom: 30px; 159 | } 160 | 161 | 162 | .shadow__btn { 163 | /* margin-top: 120px; */ 164 | padding: 8px 18px; 165 | border: none; 166 | font-size: 0.9rem; 167 | color: #fff; 168 | border-radius: 7px; 169 | letter-spacing: 2px; 170 | font-weight: 600; 171 | text-transform: uppercase; 172 | transition: 0.5s; 173 | transition-property: box-shadow; 174 | background: rgb(0, 140, 255); 175 | box-shadow: 0 0 20px rgb(0, 140, 255); 176 | text-decoration: none; 177 | } 178 | 179 | .shadow__btn:hover { 180 | box-shadow: 0 0 5px rgb(0, 140, 255), 181 | 0 0 25px rgb(0, 140, 255), 182 | 0 0 50px rgb(0, 140, 255), 183 | 0 0 100px rgb(0, 140, 255); 184 | } 185 | 186 | /* Hero mail */ 187 | .fixed-email { 188 | font-family: 'Special Gothic Expanded One', sans-serif; 189 | position: fixed; 190 | left: 0; 191 | top: 50%; 192 | transform: translateY(-50%) rotate(0deg); 193 | transform-origin: left center; 194 | writing-mode: vertical-rl; 195 | text-orientation: mixed; 196 | font-size: 0.8rem; 197 | color: #1DCD9F; 198 | text-decoration: none; 199 | letter-spacing: 2px; 200 | z-index: 999; 201 | transition: color 0.3s ease; 202 | padding: 5px; 203 | } 204 | 205 | .fixed-email:hover { 206 | cursor: pointer; 207 | } 208 | 209 | 210 | /* About me */ 211 | /* Removed old dbutton styles - replaced with animated download button */ 212 | 213 | /* Journey Section */ 214 | .group { 215 | transition: all 0.3s ease-in-out; 216 | } 217 | 218 | /* Mobile menu */ 219 | #mobileMenu a { 220 | color: white; 221 | text-decoration: none; 222 | transition: all 0.3s ease; 223 | } 224 | #mobileMenu a:hover { 225 | color: #0d6efd; 226 | } 227 | 228 | 229 | /* Hero section */ 230 | .hero { 231 | min-height: 90vh; 232 | gap: 3rem; 233 | flex-wrap: wrap; 234 | } 235 | 236 | .hero-left { 237 | flex: 1 1 45%; 238 | } 239 | 240 | .hero-right { 241 | flex: 1 1 45%; 242 | display: flex; 243 | justify-content: center; 244 | align-items: center; 245 | } 246 | 247 | .code-box { 248 | background-color: #1e1e1e; 249 | color: #dcdcdc; 250 | width: 100%; 251 | max-width: 500px; 252 | font-family: "Special Gothic Expanded One", sans-serif; font-size: 1rem; 253 | overflow: auto; 254 | border-left: 4px solid #0d6efd; 255 | transition: transform 0.3s ease; 256 | } 257 | 258 | .code-box:hover { 259 | transform: scale(1.03); 260 | } 261 | 262 | .view-projects-btn { 263 | transition: all 0.3s ease; 264 | } 265 | 266 | .view-projects-btn:hover { 267 | transform: scale(1.05); 268 | background-color: #0d6efd; 269 | color: white; 270 | } 271 | 272 | /* About Section */ 273 | #about i{ 274 | font-size: 30px; 275 | } 276 | 277 | /* Tech Stack */ 278 | #techstack i { 279 | font-size: 50px; 280 | } 281 | 282 | 283 | #framer{ 284 | 285 | color: white; 286 | } 287 | 288 | /* Animated Social Icons */ 289 | ul { 290 | list-style: none; 291 | } 292 | 293 | li::after { 294 | content: ""; 295 | display: block; 296 | height: 0px; 297 | transition: height 0.3s ease-in-out; 298 | pointer-events: none; 299 | } 300 | 301 | li:hover::after { 302 | height: 10px; 303 | } 304 | 305 | .example-2 { 306 | display: flex; 307 | justify-content: center; 308 | align-items: center; 309 | margin-top: 1.5rem; 310 | padding-bottom: 1.5rem; 311 | /* margin-bottom: 1.5rem; */ 312 | } 313 | 314 | .example-2 .icon-content { 315 | margin: 0 10px; 316 | position: relative; 317 | } 318 | 319 | .example-2 .icon-content .tooltip { 320 | position: absolute; 321 | bottom: -30px; 322 | left: 50%; 323 | transform: translateX(-50%); 324 | color: #fff; 325 | padding: 6px 10px; 326 | border-radius: 5px; 327 | opacity: 0; 328 | pointer-events: none; 329 | visibility: hidden; 330 | font-size: 14px; 331 | transition: all 0.3s ease; 332 | } 333 | 334 | .example-2 .icon-content:hover .tooltip { 335 | opacity: 1; 336 | visibility: visible; 337 | bottom: -40px; 338 | } 339 | 340 | .example-2 .icon-content a { 341 | position: relative; 342 | overflow: hidden; 343 | display: flex; 344 | justify-content: center; 345 | align-items: center; 346 | width: 50px; 347 | height: 50px; 348 | border-radius: 50%; 349 | color: #4d4d4d; 350 | background-color: #fff; 351 | transition: all 0.3s ease-in-out; 352 | } 353 | 354 | .example-2 .icon-content a:hover { 355 | box-shadow: 3px 2px 45px 0px rgb(0 0 0 / 12%); 356 | } 357 | 358 | .example-2 .icon-content a svg { 359 | position: relative; 360 | z-index: 1; 361 | width: 30px; 362 | height: 30px; 363 | } 364 | 365 | .example-2 .icon-content a:hover { 366 | color: white; 367 | } 368 | 369 | .example-2 .icon-content a .filled { 370 | position: absolute; 371 | top: auto; 372 | bottom: 0; 373 | left: 0; 374 | width: 100%; 375 | height: 0; 376 | background-color: #000; 377 | transition: all 0.3s ease-in-out; 378 | } 379 | 380 | .example-2 .icon-content a:hover .filled { 381 | height: 100%; 382 | } 383 | 384 | .example-2 .icon-content a[data-social="instagram"] .filled, 385 | .example-2 .icon-content a[data-social="instagram"] ~ .tooltip { 386 | background-color: #e1306c; 387 | } 388 | 389 | .example-2 .icon-content a[data-social="linkedin"] .filled, 390 | .example-2 .icon-content a[data-social="linkedin"] ~ .tooltip { 391 | background-color: #0a66c2; 392 | } 393 | 394 | .example-2 .icon-content a[data-social="email"] .filled, 395 | .example-2 .icon-content a[data-social="email"] ~ .tooltip { 396 | background-color: #ea4335; 397 | } 398 | 399 | .example-2 .icon-content a[data-social="github"] .filled, 400 | .example-2 .icon-content a[data-social="github"] ~ .tooltip { 401 | background-color: #333; 402 | } 403 | 404 | /* Animated Download Button */ 405 | .download-container { 406 | padding: 0; 407 | margin: 0; 408 | box-sizing: border-box; 409 | font-family: Arial, Helvetica, sans-serif; 410 | display: flex; 411 | justify-content: center; 412 | align-items: center; 413 | } 414 | 415 | .download-label { 416 | background-color: transparent; 417 | border: 2px solid #1DCD9F; 418 | display: flex; 419 | align-items: center; 420 | border-radius: 50px; 421 | width: 160px; 422 | cursor: pointer; 423 | transition: all 0.4s ease; 424 | padding: 5px; 425 | position: relative; 426 | } 427 | 428 | .download-label::before { 429 | content: ""; 430 | position: absolute; 431 | top: 0; 432 | bottom: 0; 433 | left: 0; 434 | right: 0; 435 | background-color: #fff; 436 | width: 8px; 437 | height: 8px; 438 | transition: all 0.4s ease; 439 | border-radius: 100%; 440 | margin: auto; 441 | opacity: 0; 442 | visibility: hidden; 443 | } 444 | 445 | .download-label .download-input { 446 | display: none; 447 | } 448 | 449 | .download-label .download-title { 450 | font-size: 17px; 451 | color: #fff; 452 | transition: all 0.4s ease; 453 | position: absolute; 454 | right: 18px; 455 | bottom: 14px; 456 | text-align: center; 457 | } 458 | 459 | .download-label .download-title:last-child { 460 | opacity: 0; 461 | visibility: hidden; 462 | } 463 | 464 | .download-label .download-circle { 465 | height: 45px; 466 | width: 45px; 467 | border-radius: 50%; 468 | background-color: #1DCD9F; 469 | display: flex; 470 | justify-content: center; 471 | align-items: center; 472 | transition: all 0.4s ease; 473 | position: relative; 474 | box-shadow: 0 0 0 0 rgb(255, 255, 255); 475 | overflow: hidden; 476 | } 477 | 478 | .download-label .download-circle .download-icon { 479 | color: #fff; 480 | width: 30px; 481 | position: absolute; 482 | top: 50%; 483 | left: 50%; 484 | transform: translate(-50%, -50%); 485 | transition: all 0.4s ease; 486 | } 487 | 488 | .download-label .download-circle .download-square { 489 | aspect-ratio: 1; 490 | width: 15px; 491 | border-radius: 2px; 492 | background-color: #fff; 493 | opacity: 0; 494 | visibility: hidden; 495 | position: absolute; 496 | top: 50%; 497 | left: 50%; 498 | transform: translate(-50%, -50%); 499 | transition: all 0.4s ease; 500 | } 501 | 502 | .download-label .download-circle::before { 503 | content: ""; 504 | position: absolute; 505 | left: 0; 506 | top: 0; 507 | background-color: #17b890; 508 | width: 100%; 509 | height: 0; 510 | transition: all 0.4s ease; 511 | } 512 | 513 | .download-label:has(.download-input:checked) { 514 | width: 57px; 515 | animation: installed 0.4s ease 3.5s forwards; 516 | } 517 | 518 | .download-label:has(.download-input:checked)::before { 519 | animation: rotate 3s ease-in-out 0.4s forwards; 520 | } 521 | 522 | .download-label .download-input:checked + .download-circle { 523 | animation: 524 | pulse 1s forwards, 525 | circleDelete 0.2s ease 3.5s forwards; 526 | rotate: 180deg; 527 | } 528 | 529 | .download-label .download-input:checked + .download-circle::before { 530 | animation: installing 3s ease-in-out forwards; 531 | } 532 | 533 | .download-label .download-input:checked + .download-circle .download-icon { 534 | opacity: 0; 535 | visibility: hidden; 536 | } 537 | 538 | .download-label .download-input:checked ~ .download-circle .download-square { 539 | opacity: 1; 540 | visibility: visible; 541 | } 542 | 543 | .download-label .download-input:checked ~ .download-title { 544 | opacity: 0; 545 | visibility: hidden; 546 | } 547 | 548 | .download-label .download-input:checked ~ .download-title:last-child { 549 | animation: showInstalledMessage 0.4s ease 3.5s forwards; 550 | } 551 | 552 | @keyframes pulse { 553 | 0% { 554 | scale: 0.95; 555 | box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7); 556 | } 557 | 70% { 558 | scale: 1; 559 | box-shadow: 0 0 0 16px rgba(255, 255, 255, 0); 560 | } 561 | 100% { 562 | scale: 0.95; 563 | box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); 564 | } 565 | } 566 | 567 | @keyframes installing { 568 | from { 569 | height: 0; 570 | } 571 | to { 572 | height: 100%; 573 | } 574 | } 575 | 576 | @keyframes rotate { 577 | 0% { 578 | transform: rotate(-90deg) translate(27px) rotate(0); 579 | opacity: 1; 580 | visibility: visible; 581 | } 582 | 99% { 583 | transform: rotate(270deg) translate(27px) rotate(270deg); 584 | opacity: 1; 585 | visibility: visible; 586 | } 587 | 100% { 588 | opacity: 0; 589 | visibility: hidden; 590 | } 591 | } 592 | 593 | @keyframes installed { 594 | 100% { 595 | width: 150px; 596 | border-color: #17b890; 597 | } 598 | } 599 | 600 | @keyframes circleDelete { 601 | 100% { 602 | opacity: 0; 603 | visibility: hidden; 604 | } 605 | } 606 | 607 | @keyframes showInstalledMessage { 608 | 100% { 609 | opacity: 1; 610 | visibility: visible; 611 | right: 56px; 612 | } 613 | } 614 | 615 | /* Ensure particles work with locomotive scroll */ 616 | #particles-hero, 617 | #particles-projects { 618 | position: absolute !important; 619 | z-index: 0; 620 | } 621 | 622 | /* Custom Cursor */ 623 | * { 624 | cursor: url('./assets/cursor.png'), auto; 625 | } 626 | 627 | /* Custom cursor for interactive elements */ 628 | a, button, .button, .shadow__btn, .download-label, 629 | .project-card, .upcoming-card, .journey-card, 630 | .example-2 .icon-content a, 631 | .category-label, 632 | input[type="checkbox"], 633 | [data-scroll] { 634 | cursor: url('./assets/cursor.png'), pointer; 635 | } 636 | 637 | /* Ensure cursor works on all clickable elements */ 638 | [onclick], [role="button"], [tabindex] { 639 | cursor: url('./assets/cursor.png'), pointer; 640 | } 641 | 642 | /* Performance Optimizations */ 643 | 644 | /* Lazy loading for images */ 645 | .lazy-image { 646 | opacity: 0; 647 | transition: opacity 0.3s ease-in-out; 648 | } 649 | 650 | .lazy-image.loaded { 651 | opacity: 1; 652 | } 653 | 654 | /* Reduced motion support */ 655 | @media (prefers-reduced-motion: reduce) { 656 | *, 657 | *::before, 658 | *::after { 659 | animation-duration: 0.01ms !important; 660 | animation-iteration-count: 1 !important; 661 | transition-duration: 0.01ms !important; 662 | scroll-behavior: auto !important; 663 | } 664 | 665 | .loading-text span, 666 | .button .hover-text, 667 | .shadow__btn, 668 | .download-container, 669 | .project-card, 670 | .journey-card { 671 | animation: none !important; 672 | transition: none !important; 673 | } 674 | } 675 | 676 | /* Optimize animations for better performance */ 677 | .project-card, 678 | .journey-card, 679 | .upcoming-card { 680 | will-change: transform; 681 | backface-visibility: hidden; 682 | transform: translateZ(0); 683 | } 684 | 685 | /* Smooth scrolling optimization */ 686 | html { 687 | scroll-behavior: smooth; 688 | scroll-padding-top: 80px; /* Account for fixed header if any */ 689 | } 690 | 691 | /* Font loading optimization */ 692 | @font-face { 693 | font-family: 'Special Gothic Expanded One'; 694 | font-display: swap; 695 | src: url('https://fonts.googleapis.com/css2?family=Special+Gothic+Expanded+One&display=swap'); 696 | } 697 | 698 | /* Critical CSS for above-the-fold content */ 699 | .hero-section { 700 | contain: layout style paint; 701 | } 702 | 703 | /* Optimize particle animations */ 704 | #particles-hero, 705 | #particles-projects { 706 | contain: layout style paint; 707 | will-change: transform; 708 | } 709 | 710 | /* Contact form optimizations */ 711 | .contact-form input, 712 | .contact-form textarea, 713 | .contact-form select { 714 | contain: layout style; 715 | } 716 | 717 | /* Loading state optimizations */ 718 | #loading { 719 | contain: layout style paint; 720 | } 721 | 722 | /* Scroll indicator optimization */ 723 | #scroll-indicator { 724 | contain: layout style; 725 | will-change: height; 726 | } 727 | 728 | /* Custom cursor optimization */ 729 | * { 730 | cursor: url('./assets/cursor.png'), auto; 731 | } 732 | 733 | /* Focus management for accessibility */ 734 | *:focus { 735 | outline: 2px solid #1DCD9F; 736 | outline-offset: 2px; 737 | } 738 | 739 | /* Skip to content link for accessibility */ 740 | .skip-link { 741 | position: absolute; 742 | top: -40px; 743 | left: 6px; 744 | background: #1DCD9F; 745 | color: white; 746 | padding: 8px; 747 | text-decoration: none; 748 | border-radius: 4px; 749 | z-index: 10000; 750 | } 751 | 752 | .skip-link:focus { 753 | top: 6px; 754 | } 755 | 756 | /* Print styles */ 757 | @media print { 758 | .no-print { 759 | display: none !important; 760 | } 761 | 762 | body { 763 | background: white !important; 764 | color: black !important; 765 | } 766 | 767 | .project-card, 768 | .journey-card { 769 | break-inside: avoid; 770 | } 771 | } 772 | 773 | /* Back to Top Button */ 774 | .wrapper { 775 | display: flex; 776 | align-items: center; 777 | justify-content: center; 778 | position: fixed; 779 | bottom: 30px; 780 | right: 30px; 781 | z-index: 1000; 782 | } 783 | 784 | 785 | .back2top-button { 786 | width: 40px; 787 | height: 40px; 788 | border-radius: 50%; 789 | background-color: rgb(20, 20, 20); 790 | border: none; 791 | font-weight: 600; 792 | display: flex; 793 | align-items: center; 794 | justify-content: center; 795 | box-shadow: 0px 0px 0px 4px rgba(29, 205, 159, 0.253); 796 | cursor: pointer; 797 | transition: all 0.3s ease; 798 | overflow: hidden; 799 | position: relative; 800 | opacity: 0; 801 | visibility: hidden; 802 | transform: translateY(20px); 803 | } 804 | 805 | .back2top-button.show { 806 | opacity: 1; 807 | visibility: visible; 808 | transform: translateY(0); 809 | } 810 | 811 | .back2top-button:hover { 812 | width: 140px; 813 | border-radius: 50px; 814 | background-color: #1DCD9F; 815 | box-shadow: 0px 0px 0px 4px rgba(29, 205, 159, 0.4); 816 | } 817 | 818 | .svgIcon { 819 | width: 12px; 820 | transition: transform 0.3s ease; 821 | } 822 | 823 | .back2top-button:hover .svgIcon { 824 | transform: translateY(-220%); 825 | } 826 | 827 | .svgIcon path { 828 | fill: white; 829 | } 830 | 831 | .button-label { 832 | position: absolute; 833 | bottom: -20px; 834 | color: white; 835 | font-size: 0px; 836 | opacity: 0; 837 | transition: all 0.3s ease; 838 | white-space: nowrap; 839 | } 840 | 841 | .back2top-button:hover .button-label { 842 | font-size: 13px; 843 | opacity: 1; 844 | bottom: unset; 845 | } 846 | 847 | /* Responsive adjustments */ 848 | @media (max-width: 768px) { 849 | .wrapper { 850 | bottom: 20px; 851 | right: 20px; 852 | } 853 | .back2top-button { 854 | width: 45px; 855 | height: 45px; 856 | } 857 | 858 | .back2top-button:hover { 859 | width: 120px; 860 | } 861 | } 862 | 863 | /* Form validation styles */ 864 | .validation-error { 865 | animation: slideIn 0.3s ease-out; 866 | font-size: 0.875rem; 867 | line-height: 1.25rem; 868 | margin-top: 0.25rem; 869 | padding: 0.5rem; 870 | border-radius: 0.375rem; 871 | background-color: rgba(239, 68, 68, 0.1); 872 | border-left: 3px solid #ef4444; 873 | } 874 | 875 | .validation-success { 876 | animation: slideIn 0.3s ease-out; 877 | font-size: 0.875rem; 878 | line-height: 1.25rem; 879 | margin-top: 0.25rem; 880 | padding: 0.5rem; 881 | border-radius: 0.375rem; 882 | background-color: rgba(34, 197, 94, 0.1); 883 | border-left: 3px solid #22c55e; 884 | } 885 | 886 | @keyframes slideIn { 887 | from { 888 | opacity: 0; 889 | transform: translateY(-10px); 890 | } 891 | to { 892 | opacity: 1; 893 | transform: translateY(0); 894 | } 895 | } 896 | 897 | /* Enhanced form input styles */ 898 | .contact-form input:focus, 899 | .contact-form textarea:focus, 900 | .contact-form select:focus { 901 | outline: none; 902 | border-color: #1DCD9F; 903 | box-shadow: 0 0 0 3px rgba(29, 205, 159, 0.1); 904 | transition: all 0.3s ease; 905 | } 906 | 907 | .contact-form input.border-red-500, 908 | .contact-form textarea.border-red-500 { 909 | border-color: #ef4444; 910 | box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); 911 | } 912 | 913 | .contact-form input.border-green-500, 914 | .contact-form textarea.border-green-500 { 915 | border-color: #22c55e; 916 | box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.1); 917 | } 918 | 919 | /* Form validation icon styles */ 920 | .validation-success::before { 921 | content: "✓"; 922 | margin-right: 0.5rem; 923 | font-weight: bold; 924 | color: #22c55e; 925 | } 926 | 927 | .validation-error::before { 928 | content: "⚠"; 929 | margin-right: 0.5rem; 930 | font-weight: bold; 931 | color: #ef4444; 932 | } 933 | 934 | /* Responsive validation messages */ 935 | @media (max-width: 768px) { 936 | .validation-error, 937 | .validation-success { 938 | font-size: 0.8rem; 939 | padding: 0.375rem; 940 | } 941 | } -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | // Scroll Progress Bar Logic 2 | window.addEventListener("scroll", () => { 3 | const scrollTop = window.scrollY; 4 | const docHeight = document.documentElement.scrollHeight - window.innerHeight; 5 | const scrollPercent = (scrollTop / docHeight) * 100; 6 | 7 | const progressBar = document.getElementById("scroll-indicator"); 8 | progressBar.style.height = `${scrollPercent}%`; 9 | }); 10 | 11 | // Loading animation 12 | const letters = document.querySelectorAll(".loading-text span"); 13 | 14 | // Animate each letter with stagger 15 | gsap.to(letters, { 16 | opacity: 1, 17 | duration: 1.2, 18 | stagger: 0.15, 19 | onUpdate: function () { 20 | letters.forEach((el, i) => { 21 | gsap.to(el, { 22 | color: "#ffffff", 23 | duration: 0.2, 24 | delay: i * 0.15, 25 | }); 26 | gsap.to(el, { 27 | color: "rgba(255,255,255,0.1)", 28 | duration: 0.2, 29 | delay: i * 0.15 + 0.4, 30 | }); 31 | gsap.to(el.querySelector("::after"), { 32 | opacity: 1, 33 | duration: 0.2, 34 | delay: i * 0.15, 35 | }); 36 | }); 37 | }, 38 | onComplete: () => { 39 | gsap.to("#loading", { 40 | opacity: 0, 41 | duration: 1, 42 | delay: 0.5, 43 | onComplete: () => { 44 | document.getElementById("loading").style.display = "none"; 45 | }, 46 | }); 47 | }, 48 | }); 49 | 50 | 51 | // Animation for Hero Text 52 | gsap.from(".hero-left", { 53 | opacity: 0, 54 | x: -50, 55 | duration: 1.2, 56 | ease: "power3.out", 57 | }); 58 | 59 | gsap.from(".hero-right", { 60 | opacity: 0, 61 | x: 50, 62 | duration: 1.2, 63 | ease: "power3.out", 64 | delay: 0.3, 65 | }); 66 | 67 | gsap.utils.toArray(".journey-card").forEach((card, index) => { 68 | gsap.from(card, { 69 | opacity: 0, 70 | y: 80, 71 | duration: .4, 72 | ease: "power3.out", 73 | scrollTrigger: { 74 | trigger: card, 75 | start: "top 85%", 76 | toggleActions: "play none none reverse", 77 | }, 78 | delay: index * 0.1, 79 | }); 80 | }); 81 | 82 | // HERO SECTION PARTICLES 83 | particlesJS("particles-hero", { 84 | "particles": { 85 | "number": { 86 | "value": 200, 87 | "density": { "enable": true, "value_area": 800 } 88 | }, 89 | "color": { "value": "#ffffff" }, 90 | "opacity": { "value": 0.7, "random": false }, 91 | "size": { "value": 4, "random": true }, 92 | "line_linked": { "enable": false }, 93 | "move": { 94 | "enable": true, 95 | "speed": 1, 96 | "direction": "bottom", 97 | "out_mode": "out" 98 | } 99 | }, 100 | "interactivity": { 101 | "events": { 102 | "onhover": { "enable": false }, 103 | "onclick": { "enable": false } 104 | } 105 | }, 106 | "retina_detect": true 107 | }); 108 | 109 | 110 | 111 | particlesJS("particles-projects", { 112 | "particles": { 113 | "number": { "value": 50 }, 114 | "color": { "value": "ffffff" }, 115 | "shape": { "type": "circle" }, 116 | "opacity": { 117 | "value": 0.5, 118 | "random": true 119 | }, 120 | "size": { 121 | "value": 4, 122 | "random": true 123 | }, 124 | "line_linked": { 125 | "enable": true, 126 | "distance": 150, 127 | "color": "ffffff", 128 | "opacity": 0.4, 129 | "width": 1 130 | }, 131 | "move": { 132 | "enable": true, 133 | "speed": 3, 134 | "direction": "none", 135 | "out_mode": "out" 136 | } 137 | }, 138 | "interactivity": { 139 | "detect_on": "canvas", 140 | "events": { 141 | "onhover": { "enable": true, "mode": "grab" }, 142 | "onclick": { "enable": true, "mode": "push" } 143 | }, 144 | "modes": { 145 | "grab": { 146 | "distance": 140, 147 | "line_linked": { "opacity": 1 } 148 | }, 149 | "push": { "particles_nb": 4 } 150 | } 151 | }, 152 | "retina_detect": true 153 | }); 154 | 155 | 156 | gsap.registerPlugin(ScrollTrigger); 157 | 158 | gsap.utils.toArray('.fade-in').forEach((el) => { 159 | gsap.from(el, { 160 | scrollTrigger: { 161 | trigger: el, 162 | start: "top 85%", 163 | toggleActions: "play none none none" 164 | }, 165 | opacity: 0, 166 | y: 40, 167 | duration: 1.2, 168 | ease: "power3.out", 169 | }); 170 | }); 171 | 172 | gsap.from(".project-card", { 173 | scrollTrigger: { 174 | trigger: ".project-card", 175 | start: "top 85%", 176 | toggleActions: "play none none reset" 177 | }, 178 | opacity: 0, 179 | y: 60, 180 | duration: 1, 181 | ease: "power3.out" 182 | }); 183 | 184 | gsap.from("#about-img", { 185 | scrollTrigger: { 186 | trigger: "#about-img", 187 | start: "top 80%", 188 | toggleActions: "play none none reset", 189 | }, 190 | opacity: 0, 191 | x: -100, 192 | duration: .4, 193 | ease: "power3.out" 194 | }); 195 | 196 | 197 | gsap.from("#about-text", { 198 | scrollTrigger: { 199 | trigger: "#about-text", 200 | start: "top 80%", 201 | toggleActions: "play none none reset", 202 | }, 203 | opacity: 0, 204 | y: 50, 205 | duration: .4, 206 | ease: "power3.out", 207 | delay: 0.2 208 | }); 209 | 210 | gsap.from("#techstack h2", { 211 | scrollTrigger: { 212 | trigger: "#techstack", 213 | start: "top 80%", 214 | toggleActions: "play none none reset" 215 | }, 216 | opacity: 0, 217 | y: -40, 218 | duration: 1.2, 219 | ease: "power3.out" 220 | }); 221 | 222 | gsap.utils.toArray("#techstack .group").forEach((card, i) => { 223 | gsap.from(card, { 224 | scrollTrigger: { 225 | trigger: card, 226 | start: "top 85%", 227 | toggleActions: "play none none reset" 228 | }, 229 | opacity: 0, 230 | y: 50, 231 | duration: 1, 232 | ease: "power3.out", 233 | delay: i * 0.1, 234 | }); 235 | }); 236 | 237 | gsap.utils.toArray('.tech-category').forEach((section, index) => { 238 | gsap.from(section, { 239 | opacity: 0, 240 | y: 60, 241 | duration: 0.8, 242 | ease: "power3.out", 243 | scrollTrigger: { 244 | trigger: section, 245 | start: "top 80%", 246 | toggleActions: "play none none reverse" 247 | } 248 | }); 249 | }); 250 | 251 | gsap.utils.toArray('.reveal-section').forEach(section => { 252 | gsap.from(section, { 253 | opacity: 0, 254 | y: 60, 255 | duration: 1, 256 | scrollTrigger: { 257 | trigger: section, 258 | start: "top 80%", 259 | toggleActions: "play none none reset" 260 | } 261 | }); 262 | }); 263 | 264 | // Up coming projects 265 | 266 | gsap.utils.toArray(".upcoming-card").forEach((card, i) => { 267 | gsap.from(card, { 268 | scrollTrigger: { 269 | trigger: "#upcoming-projects", 270 | start: "top 85%", 271 | toggleActions: "play none none reset" 272 | }, 273 | opacity: 0, 274 | y: 60, 275 | duration: 1, 276 | ease: "power3.out", 277 | delay: i * 0.15, 278 | }); 279 | }); 280 | 281 | // Animated Download Button Functionality 282 | document.addEventListener('DOMContentLoaded', function() { 283 | const downloadInput = document.querySelector('.download-label .download-input'); 284 | const downloadLink = document.querySelector('a[download]'); 285 | 286 | if (downloadInput && downloadLink) { 287 | downloadInput.addEventListener('change', function() { 288 | if (this.checked) { 289 | // Trigger the download after animation starts 290 | setTimeout(() => { 291 | // Create a temporary link to trigger download 292 | const tempLink = document.createElement('a'); 293 | tempLink.href = downloadLink.href; 294 | tempLink.download = downloadLink.download || 'resume.pdf'; 295 | document.body.appendChild(tempLink); 296 | tempLink.click(); 297 | document.body.removeChild(tempLink); 298 | 299 | // Reset the checkbox after animation completes 300 | setTimeout(() => { 301 | this.checked = false; 302 | }, 4000); // Reset after animation completes 303 | }, 500); // Small delay to let animation start 304 | } 305 | }); 306 | } 307 | }); 308 | 309 | // Contact Form Functionality 310 | document.addEventListener('DOMContentLoaded', function() { 311 | const contactForm = document.getElementById('contactForm'); 312 | const submitBtn = document.getElementById('submitBtn'); 313 | const submitText = document.getElementById('submitText'); 314 | const submitLoading = document.getElementById('submitLoading'); 315 | const formMessage = document.getElementById('formMessage'); 316 | const messageText = document.getElementById('messageText'); 317 | const messageInput = document.getElementById('message'); 318 | 319 | // Gibberish detection functions 320 | function detectGibberish(text) { 321 | const errors = []; 322 | 323 | // Remove extra whitespace and normalize 324 | const cleanText = text.trim().replace(/\s+/g, ' '); 325 | 326 | 327 | 328 | // 1. Check minimum length 329 | if (cleanText.length < 10) { 330 | errors.push('Message must be at least 10 characters long'); 331 | } 332 | 333 | // 2. Check minimum word count 334 | const words = cleanText.split(' ').filter(word => word.length > 0); 335 | if (words.length < 3) { 336 | errors.push('Message must contain at least 3 words'); 337 | } 338 | 339 | // 3. Check for excessive character repetition (e.g., "aaaaaa", "!!!!!!") 340 | const charRepetition = /(.)\1{4,}/g; 341 | if (charRepetition.test(cleanText)) { 342 | errors.push('Message contains too many repeated characters'); 343 | } 344 | 345 | // 4. Check for excessive word repetition 346 | const wordCounts = {}; 347 | words.forEach(word => { 348 | const cleanWord = word.toLowerCase().replace(/[^\w]/g, ''); 349 | if (cleanWord.length > 2) { 350 | wordCounts[cleanWord] = (wordCounts[cleanWord] || 0) + 1; 351 | } 352 | }); 353 | 354 | const repeatedWords = Object.entries(wordCounts).filter(([word, count]) => count > 2); 355 | if (repeatedWords.length > 0) { 356 | errors.push('Message contains too many repeated words'); 357 | } 358 | 359 | // 5. Check for random character sequences (e.g., "asdfgh", "qwerty") 360 | const randomPatterns = [ 361 | /asdfgh/i, /qwerty/i, /zxcvbn/i, /123456/i, /abcdef/i, 362 | /[!@#$%^&*]{3,}/ 363 | ]; 364 | 365 | for (const pattern of randomPatterns) { 366 | if (pattern.test(cleanText)) { 367 | errors.push('Message contains random character sequences'); 368 | break; 369 | } 370 | } 371 | 372 | // 5.5. Check for consecutive numbers (but allow normal text) 373 | const consecutiveNumbers = /[0-9]{4,}/; 374 | if (consecutiveNumbers.test(cleanText)) { 375 | errors.push('Message contains random number sequences'); 376 | } 377 | 378 | // 6. Check for meaningful content (at least some words with 3+ characters) 379 | const meaningfulWords = words.filter(word => word.length >= 3); 380 | if (meaningfulWords.length < 2) { 381 | errors.push('Message must contain meaningful words (3+ characters)'); 382 | } 383 | 384 | // 7. Check for excessive punctuation 385 | const punctuationCount = (cleanText.match(/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/g) || []).length; 386 | if (punctuationCount > cleanText.length * 0.3) { 387 | errors.push('Message contains too much punctuation'); 388 | } 389 | 390 | // 8. Check for all caps (shouting) 391 | const upperCaseWords = words.filter(word => word === word.toUpperCase() && word.length > 2); 392 | if (upperCaseWords.length > words.length * 0.5) { 393 | errors.push('Please avoid typing in all capital letters'); 394 | } 395 | 396 | return { 397 | isValid: errors.length === 0, 398 | errors: errors 399 | }; 400 | } 401 | 402 | // Real-time validation 403 | if (messageInput) { 404 | let validationTimeout; 405 | 406 | messageInput.addEventListener('input', function() { 407 | clearTimeout(validationTimeout); 408 | 409 | validationTimeout = setTimeout(() => { 410 | const validation = detectGibberish(this.value); 411 | const messageContainer = this.parentElement; 412 | 413 | // Remove existing validation messages 414 | const existingError = messageContainer.querySelector('.validation-error'); 415 | if (existingError) { 416 | existingError.remove(); 417 | } 418 | 419 | // Remove existing validation classes 420 | this.classList.remove('border-red-500', 'border-green-500'); 421 | 422 | if (this.value.trim() === '') { 423 | return; // Don't show validation for empty field 424 | } 425 | 426 | if (!validation.isValid) { 427 | this.classList.add('border-red-500'); 428 | const errorDiv = document.createElement('div'); 429 | errorDiv.className = 'validation-error text-red-500 text-sm mt-1'; 430 | errorDiv.innerHTML = validation.errors.join('
'); 431 | messageContainer.appendChild(errorDiv); 432 | 433 | // Auto-remove error message after 4 seconds 434 | setTimeout(() => { 435 | if (errorDiv.parentNode) { 436 | errorDiv.remove(); 437 | } 438 | }, 2500); 439 | } else { 440 | this.classList.add('border-green-500'); 441 | const successDiv = document.createElement('div'); 442 | successDiv.className = 'validation-success text-green-500 text-sm mt-1'; 443 | successDiv.textContent = 'Message looks good!'; 444 | messageContainer.appendChild(successDiv); 445 | 446 | // Auto-remove success message after 3 seconds 447 | setTimeout(() => { 448 | if (successDiv.parentNode) { 449 | successDiv.remove(); 450 | } 451 | }, 1500); 452 | } 453 | }, 500); // Debounce validation 454 | }); 455 | 456 | // Clear validation on focus 457 | messageInput.addEventListener('focus', function() { 458 | const existingError = this.parentElement.querySelector('.validation-error'); 459 | const existingSuccess = this.parentElement.querySelector('.validation-success'); 460 | if (existingError) existingError.remove(); 461 | if (existingSuccess) existingSuccess.remove(); 462 | this.classList.remove('border-red-500', 'border-green-500'); 463 | }); 464 | } 465 | 466 | if (contactForm) { 467 | contactForm.addEventListener('submit', async function(e) { 468 | e.preventDefault(); 469 | 470 | // Show loading state 471 | submitBtn.disabled = true; 472 | submitText.classList.add('hidden'); 473 | submitLoading.classList.remove('hidden'); 474 | 475 | // Get form data 476 | const formData = new FormData(contactForm); 477 | 478 | // Validate message before submission 479 | const message = formData.get('message'); 480 | const validation = detectGibberish(message); 481 | 482 | if (!validation.isValid) { 483 | showMessage(`Please fix the following issues:
${validation.errors.join('
')}`, 'error'); 484 | // Reset button state 485 | submitBtn.disabled = false; 486 | submitText.classList.remove('hidden'); 487 | submitLoading.classList.add('hidden'); 488 | return; 489 | } 490 | const data = { 491 | firstName: formData.get('firstName'), 492 | lastName: formData.get('lastName'), 493 | email: formData.get('email'), 494 | subject: formData.get('subject'), 495 | message: formData.get('message') 496 | }; 497 | 498 | try { 499 | // Option 1: Using Formspree (you need to create your own endpoint) 500 | // Replace 'YOUR_FORMSPREE_ENDPOINT' with your actual Formspree endpoint 501 | const response = await fetch('https://formspree.io/f/mjkrlgar', { 502 | method: 'POST', 503 | headers: { 504 | 'Content-Type': 'application/json', 505 | }, 506 | body: JSON.stringify(data) 507 | }); 508 | 509 | if (response.ok) { 510 | showMessage('Thank you! Your message has been sent successfully. I\'ll get back to you soon!', 'success'); 511 | contactForm.reset(); 512 | } else { 513 | throw new Error('Failed to send message'); 514 | } 515 | } catch (error) { 516 | console.error('Error:', error); 517 | 518 | // Fallback: Send email directly (this will open user's email client) 519 | const emailSubject = encodeURIComponent(`Portfolio Contact: ${data.subject}`); 520 | const emailBody = encodeURIComponent(` 521 | Name: ${data.firstName} ${data.lastName} 522 | Email: ${data.email} 523 | Subject: ${data.subject} 524 | 525 | Message: 526 | ${data.message} 527 | `); 528 | 529 | const mailtoLink = `mailto:abhijeetbhale7@gmail.com?subject=${emailSubject}&body=${emailBody}`; 530 | 531 | showMessage(`Form submission failed. Click here to send email directly or try again later.`, 'error'); 532 | } finally { 533 | // Reset button state 534 | submitBtn.disabled = false; 535 | submitText.classList.remove('hidden'); 536 | submitLoading.classList.add('hidden'); 537 | } 538 | }); 539 | } 540 | 541 | function showMessage(text, type) { 542 | messageText.innerHTML = text; 543 | formMessage.className = `mt-4 p-4 rounded-lg ${type === 'success' ? 'bg-green-100 text-green-700 border border-green-200' : 'bg-red-100 text-red-700 border border-red-200'}`; 544 | formMessage.classList.remove('hidden'); 545 | 546 | // Auto-hide message after 8 seconds 547 | setTimeout(() => { 548 | formMessage.classList.add('hidden'); 549 | }, 8000); 550 | } 551 | }); 552 | 553 | // Performance Optimizations - Lazy Loading 554 | document.addEventListener('DOMContentLoaded', function() { 555 | // Lazy loading for images 556 | const lazyImages = document.querySelectorAll('img[data-src]'); 557 | 558 | const imageObserver = new IntersectionObserver((entries, observer) => { 559 | entries.forEach(entry => { 560 | if (entry.isIntersecting) { 561 | const img = entry.target; 562 | img.src = img.dataset.src; 563 | img.classList.add('loaded'); 564 | observer.unobserve(img); 565 | } 566 | }); 567 | }); 568 | 569 | lazyImages.forEach(img => { 570 | imageObserver.observe(img); 571 | }); 572 | 573 | // Preload critical images 574 | const criticalImages = [ 575 | './assets/AbhijeetBhalePortfolio.jpg', 576 | './assets/cursor.png' 577 | ]; 578 | 579 | criticalImages.forEach(src => { 580 | const link = document.createElement('link'); 581 | link.rel = 'preload'; 582 | link.as = 'image'; 583 | link.href = src; 584 | document.head.appendChild(link); 585 | }); 586 | 587 | // Optimize scroll performance 588 | let ticking = false; 589 | 590 | function updateScrollIndicator() { 591 | const scrollTop = window.scrollY; 592 | const docHeight = document.documentElement.scrollHeight - window.innerHeight; 593 | const scrollPercent = (scrollTop / docHeight) * 100; 594 | 595 | const progressBar = document.getElementById("scroll-indicator"); 596 | if (progressBar) { 597 | progressBar.style.height = `${scrollPercent}%`; 598 | } 599 | 600 | ticking = false; 601 | } 602 | 603 | window.addEventListener("scroll", () => { 604 | if (!ticking) { 605 | requestAnimationFrame(updateScrollIndicator); 606 | ticking = true; 607 | } 608 | }); 609 | 610 | // Service Worker registration for PWA features 611 | if ('serviceWorker' in navigator) { 612 | window.addEventListener('load', () => { 613 | navigator.serviceWorker.register('/sw.js') 614 | .then(registration => { 615 | console.log('SW registered: ', registration); 616 | }) 617 | .catch(registrationError => { 618 | console.log('SW registration failed: ', registrationError); 619 | }); 620 | }); 621 | } 622 | }); 623 | 624 | // GitHub API Integration 625 | document.addEventListener('DOMContentLoaded', function() { 626 | const username = 'abhijeetBhale'; 627 | 628 | // GitHub API endpoints 629 | const endpoints = { 630 | user: `https://api.github.com/users/${username}`, 631 | repos: `https://api.github.com/users/${username}/repos`, 632 | activity: `https://api.github.com/users/${username}/events` 633 | }; 634 | 635 | // Fetch GitHub user data 636 | async function fetchGitHubData() { 637 | try { 638 | const [userResponse, reposResponse] = await Promise.all([ 639 | fetch(endpoints.user), 640 | fetch(endpoints.repos) 641 | ]); 642 | 643 | if (userResponse.ok && reposResponse.ok) { 644 | const userData = await userResponse.json(); 645 | const reposData = await reposResponse.json(); 646 | 647 | // Update stats 648 | document.getElementById('githubRepos').textContent = userData.public_repos; 649 | document.getElementById('githubFollowers').textContent = userData.followers; 650 | 651 | // Calculate total stars 652 | const totalStars = reposData.reduce((sum, repo) => sum + repo.stargazers_count, 0); 653 | document.getElementById('githubStars').textContent = totalStars; 654 | 655 | // Calculate recent commits (last 30 days) 656 | const thirtyDaysAgo = new Date(); 657 | thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); 658 | 659 | const commitsResponse = await fetch(`https://api.github.com/search/commits?q=author:${username}+committer-date:>${thirtyDaysAgo.toISOString().split('T')[0]}`); 660 | if (commitsResponse.ok) { 661 | const commitsData = await commitsResponse.json(); 662 | document.getElementById('githubCommits').textContent = commitsData.total_count; 663 | } 664 | 665 | // Load activity feed 666 | loadGitHubActivity(); 667 | 668 | // Load language stats 669 | loadGitHubLanguages(reposData); 670 | } 671 | } catch (error) { 672 | console.error('Error fetching GitHub data:', error); 673 | // Show fallback data 674 | document.getElementById('githubRepos').textContent = '15+'; 675 | document.getElementById('githubStars').textContent = '25+'; 676 | document.getElementById('githubFollowers').textContent = '10+'; 677 | document.getElementById('githubCommits').textContent = '50+'; 678 | } 679 | } 680 | 681 | // Load GitHub activity 682 | async function loadGitHubActivity() { 683 | try { 684 | const response = await fetch(endpoints.activity); 685 | if (response.ok) { 686 | const activityData = await response.json(); 687 | const activityContainer = document.getElementById('githubActivity'); 688 | 689 | // Clear loading state 690 | activityContainer.innerHTML = ''; 691 | 692 | // Show recent activity (last 5 events) 693 | const recentActivity = activityData.slice(0, 5); 694 | 695 | recentActivity.forEach(event => { 696 | const activityItem = createActivityItem(event); 697 | activityContainer.appendChild(activityItem); 698 | }); 699 | } 700 | } catch (error) { 701 | console.error('Error loading GitHub activity:', error); 702 | } 703 | } 704 | 705 | // Create activity item element 706 | function createActivityItem(event) { 707 | const item = document.createElement('div'); 708 | item.className = 'flex items-center space-x-4 p-4 bg-[#0a0a0a] rounded-lg border border-gray-800'; 709 | 710 | const eventType = event.type; 711 | const repoName = event.repo?.name || 'Unknown Repository'; 712 | const createdAt = new Date(event.created_at).toLocaleDateString(); 713 | 714 | let icon, text; 715 | 716 | switch(eventType) { 717 | case 'PushEvent': 718 | icon = 'fas fa-code'; 719 | text = `Pushed to ${repoName}`; 720 | break; 721 | case 'CreateEvent': 722 | icon = 'fas fa-plus'; 723 | text = `Created ${repoName}`; 724 | break; 725 | case 'ForkEvent': 726 | icon = 'fas fa-code-branch'; 727 | text = `Forked ${repoName}`; 728 | break; 729 | case 'WatchEvent': 730 | icon = 'fas fa-star'; 731 | text = `Starred ${repoName}`; 732 | break; 733 | default: 734 | icon = 'fas fa-circle'; 735 | text = `Activity in ${repoName}`; 736 | } 737 | 738 | item.innerHTML = ` 739 |
740 | 741 |
742 |
743 |

${text}

744 |

${createdAt}

745 |
746 | 747 | 748 | 749 | `; 750 | 751 | return item; 752 | } 753 | 754 | // Load GitHub languages 755 | function loadGitHubLanguages(reposData) { 756 | const languageStats = {}; 757 | 758 | reposData.forEach(repo => { 759 | if (repo.language) { 760 | languageStats[repo.language] = (languageStats[repo.language] || 0) + 1; 761 | } 762 | }); 763 | 764 | // Sort languages by frequency 765 | const sortedLanguages = Object.entries(languageStats) 766 | .sort(([,a], [,b]) => b - a) 767 | .slice(0, 6); 768 | 769 | const languagesContainer = document.getElementById('githubLanguages'); 770 | languagesContainer.innerHTML = ''; 771 | 772 | sortedLanguages.forEach(([language, count]) => { 773 | const languageCard = document.createElement('div'); 774 | languageCard.className = 'bg-[#111] p-4 rounded-xl border border-gray-800 text-center hover:border-[#1DCD9F] transition-all duration-300'; 775 | 776 | languageCard.innerHTML = ` 777 |
${language}
778 |
${count} repositories
779 | `; 780 | 781 | languagesContainer.appendChild(languageCard); 782 | }); 783 | } 784 | 785 | // Initialize GitHub data loading 786 | fetchGitHubData(); 787 | }); 788 | 789 | // Back to Top Button Functionality 790 | const backToTopButton = document.getElementById('backToTop'); 791 | 792 | // Show/hide button based on scroll position 793 | window.addEventListener('scroll', () => { 794 | if (window.scrollY > 300) { 795 | backToTopButton.classList.add('show'); 796 | } else { 797 | backToTopButton.classList.remove('show'); 798 | } 799 | }); 800 | 801 | // Scroll to top when button is clicked 802 | backToTopButton.addEventListener('click', () => { 803 | window.scrollTo({ 804 | top: 0, 805 | behavior: 'smooth' 806 | }); 807 | }); 808 | 809 | document.addEventListener('DOMContentLoaded', function() { 810 | const scrollBar = document.getElementById('scroll-bar'); 811 | if (scrollBar) { 812 | scrollBar.addEventListener('click', function(e) { 813 | const rect = scrollBar.getBoundingClientRect(); 814 | const clickY = e.clientY - rect.top; 815 | const percent = clickY / rect.height; 816 | const docHeight = document.documentElement.scrollHeight - window.innerHeight; 817 | const targetScroll = percent * docHeight; 818 | window.scrollTo({ 819 | top: targetScroll, 820 | behavior: 'smooth' 821 | }); 822 | }); 823 | } 824 | }); 825 | 826 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Portfolio / Abhijeet Bhale 7 | 8 | 9 | 10 | 14 | 18 | 22 | 26 | 30 | 31 | 32 | 33 | 34 | 37 | 38 |
39 |
40 | A 41 | B 42 | H 43 | I 44 | J 45 | E 46 | E 47 | T 48 |
49 |
50 | 51 | 52 |
53 | 54 |
55 | 56 | 57 |
58 |

59 | Hi, I'm 60 | 64 |

65 |

66 | An aspiring Full Stack Developer passionate about building sleek web 67 | experiences. 68 |

69 | View Projects 70 |
71 |
72 | 73 | 74 |
75 |
78 | 79 |
83 | Abhijeet Bhale 88 |
89 | 90 | 91 |
92 |

93 | I'm Abhijeet Bhale, a 94 | Full Stack Developer building creative and scalable web 95 | applications. 96 |

97 | 98 |

99 | I'm currently pursuing my B.Tech in Computer Science Engineering at 100 | Medicaps University, Indore. I specialize in both frontend and 101 | backend development, transforming ideas into functional digital 102 | experiences using modern technologies. 103 |

104 | 105 |

106 | I'm passionate about 107 | JavaScript, 108 | React, 109 | Node.js, 110 | MongoDB, and bringing 111 | smooth, responsive UIs to life with animations and performance in 112 | mind. Outside of code, I love exploring photography, tech, and new 113 | ideas. 114 |

115 | 116 | 117 | 174 | 175 | 176 | 210 |
211 |
212 |
213 | 214 |
215 |
216 |

My Journey

217 | 218 |
219 | 220 | 221 | 222 | 223 |
224 | 225 |
226 |
227 |
228 |

Internship at @AWS Cloud Foundation

229 | June 2025 - Aug 2025 230 |

Worked on AWS services, cloud deployment, and automation. Gained hands-on experience with cloud infrastructure and DevOps practices.

231 |
232 |
233 |
234 | 235 | 236 |
237 | 238 |
239 |
240 |

Internship at @ProdigyInfoTech

241 | June 2024 - Aug 2024 242 |

Worked on UI/UX design, responsive components, and integrated APIs using React and Tailwind CSS.

243 |
244 |
245 |
246 |
247 | 248 | 249 |
250 | 251 |
252 |
253 |
254 |

B.Tech – Computer Science (CSBS)

255 | Medi-Caps University, Indore (2022 - 2026) 256 |

Focused on full-stack development, AI projects, and cloud computing technologies.

257 |
258 |
259 |
260 | 261 | 262 |
263 | 264 |
265 |
266 |

High School – PCM

267 | Shree Madhav Vidhya Peeth School, Indore (2020) 268 |

Built an early interest in coding, building basic games and websites in school projects.

269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 | 277 | 278 |
279 |
280 | 281 |
282 | 283 |
284 |
FRONTEND
285 |
286 | 287 | 288 |
289 | 290 |
Javascript
291 |
React
292 | 293 |
294 | 295 | Tailwind CSS
296 |
297 | HTML
298 |
299 | 300 | CSS
301 |
302 | 303 | GSAP 304 |
305 |
306 | Framer Motion
308 |
C
309 |
C++
310 |
Bootstrap
311 |
Python
312 |
313 |
314 | 315 | 316 |
317 |
318 |
BACKEND
319 |
320 |
321 |
Node.js
322 |
Next.js
323 |
Express.js
324 |
React Router
325 |
Nodemon
326 |
327 |
328 | 329 | 330 |
331 |
332 |
DATABASE
333 |
334 |
335 |
Mongoose
336 |
MongoDB
337 |
Oracle
338 | 339 |
340 |
341 | 342 | 343 |
344 |
345 |
TOOLS
346 |
347 |
348 |
Git
349 |
Docker
350 |
GitHub
351 |
Google Cloud
352 |
AWS
353 |
354 |
355 |
356 |
357 | 358 | 359 |
360 |
361 |
362 |

GitHub Activity

363 |

My latest contributions and coding activity.

364 |
365 | 366 |
367 | 368 |
369 |
-
370 |
Public Repositories
371 |
372 | 373 |
374 |
-
375 |
Total Stars
376 |
377 | 378 |
379 |
-
380 |
Followers
381 |
382 | 383 |
384 |
-
385 |
Recent Commits
386 |
387 |
388 | 389 | 390 |
391 |
392 |

Recent Activity

393 | 394 | View Profile 395 | 396 |
397 | 398 |
399 | 400 |
401 |
402 | Loading activity... 403 |
404 |
405 |
406 | 407 | 408 |
409 |

Most Used Languages

410 |
411 | 412 |
413 |
414 |
415 |
416 | 417 | 418 |
419 |
420 |
421 |

Latest Blog Posts

422 |

Thoughts, tutorials, and insights from my journey in tech.

423 |
424 | 425 |
426 | 427 |
428 |
429 | Portfolio Website Screenshot 433 | 436 |
437 |
438 |
439 | 440 | July 1, 2025 441 | 442 | 443 | 3 min read 444 |
445 |

446 | Portfolio Website 447 |

448 |

449 | Learn the essential techniques to optimize your React applications for better performance, including memoization, code splitting, and bundle optimization. 450 |

451 |
452 | 453 | Read More 454 | 455 |
456 | 457 | 10 458 |
459 |
460 |
461 |
462 | 463 | 464 |
465 |
466 | GitHub Readme Generator 470 | 473 |
474 |
475 |
476 | 477 | July 2, 2025 478 | 479 | 480 | 1 min read 481 |
482 |

483 | GitHub Readme Generator 484 |

485 |

486 | I've created a GitHub Readme Generator to help you create and preview GitHub README files. 487 |

488 |
489 | 490 | Read More 491 | 492 |
493 | 494 | 5 495 |
496 |
497 |
498 |
499 | 500 | 501 |
502 |
503 | BookHive- Share Your Thoughts 507 | 510 |
511 |
512 |
513 | 514 | December 21, 2025 515 | 516 | 517 | 2 min read 518 |
519 |

520 | BookHive- Share Your Thoughts 521 |

522 |

523 | I've created a BookHive - Share Your Thoughts to help you connect and share books in physical form. 524 |

525 |
526 | 527 | Read More 528 | 529 |
530 | 531 | 8 532 |
533 |
534 |
535 |
536 |
537 | 538 | 539 | 545 |
546 |
547 | 548 | 549 | 550 | 551 |
552 | 553 | 554 |
555 | 556 | 557 |
558 |
559 |

Projects

560 |

Some of the things I've built.

561 |
562 | 563 |
564 | 565 | 566 | 567 |
568 | Portfolio Website Screenshot 569 |
570 |

BookHive- Share Your Thoughts

571 |

572 | A revolutionary platform for book lovers to connect, share, and discover new literary adventures through seamless borrowing and real-time communication. 573 |

574 | 575 | 576 |
577 | 578 | React 579 | React 580 | 581 | 582 | Tailwind CSS 583 | MongoDB 584 | 585 | 586 | Markdown 587 | Google Cloud 588 | 589 | 590 | Netlify 591 | Render 592 | 593 | 594 | Vite 595 | Socket.io 596 | 597 |
598 | 599 | 600 | 610 |
611 |
612 | 613 | 614 | 615 |
616 | Portfolio Website Screenshot 617 |
618 |

GitHub Readme Generator

619 |

620 | Easily create and preview GitHub README files. Generate markdown and download or copy it for your projects. 621 | Simple, fast, and no sign-up needed. 622 |

623 | 624 | 625 |
626 | 627 | React 628 | React 629 | 630 | 631 | Tailwind CSS 632 | Tailwind CSS 633 | 634 | 635 | Markdown 636 | Markdown 637 | 638 | 639 | Netlify 640 | Netlify 641 | 642 | 643 | Vite 644 | Vite 645 | 646 |
647 | 648 | 649 | 659 |
660 |
661 | 662 | 663 | 664 |
665 | Portfolio Website Screenshot 666 |
667 |

ATS Resume Checker

668 |

669 | An intelligent resume analysis tool that evaluates resumes against job descriptions using AI-powered semantic matching and provides actionable improvement suggestions. 670 |

671 | 672 | 673 |
674 | 675 | React 676 | React 677 | 678 | 679 | Tailwind CSS 680 | Tailwind CSS 681 | 682 | 683 | Markdown 684 | Open AI 685 | 686 | 687 | Netlify 688 | Render 689 | 690 | 691 | Vite 692 | Framer 693 | 694 |
695 | 696 | 697 | 707 |
708 |
709 | 710 | 711 | 712 |
713 | Portfolio Website Screenshot 714 |
715 |

Boost AI

716 |

717 | An AI productivity tool using Google Gemini for content generation and task automation. Includes real-time chat and document analysis. Fast, simple, and secure. 718 |

719 | 720 | 721 |
722 | 723 | React 724 | React 725 | 726 | 727 | MongoDB 728 | MongoDB 729 | 730 | 731 | Node.js 732 | Node.js 733 | 734 | 735 | Google 736 | Gemini 737 | 738 | 739 | Express 740 | Express 741 | 742 |
743 | 744 | 745 | 755 |
756 |
757 | 758 | 759 | 760 |
761 | Finger Fiasco Screenshot 762 |
763 |

Pinterest Clone

764 |

765 | A visually rich and fully responsive Pinterest Clone crafted using React, React Router, and Tailwind CSS, offering a seamless browsing experience with smooth navigation and a modern UI design. 766 |

767 | 768 | 769 |
770 | 771 | React 772 | React 773 | 774 | 775 | TailwindCSS 776 | Tailwindcss 777 | 778 | 779 | ReactRouter 780 | ReactRouter 781 | 782 | 783 | MongoDB 784 | MongoDB 785 | 786 | 787 | Node.js 788 | Node.js 789 | 790 |
791 | 792 | 793 | 803 |
804 |
805 | 806 | 807 | 808 |
809 | Finger Fiasco Screenshot 810 |
811 |

Finger Fiasco

812 |

813 | A fast-paced typing game to test and improve your typing speed. Built using HTML, CSS, JavaScript with custom game logic and animated UI. 814 |

815 | 816 | 817 |
818 | 819 | HTML 820 | HTML 821 | 822 | 823 | CSS 824 | CSS 825 | 826 | 827 | Bootstrap 828 | Bootstrap 829 | 830 | 831 | JavaScript 832 | JavaScript 833 | 834 |
835 | 836 | 837 | 847 |
848 |
849 | 850 | 851 | 852 |
853 | Portfolio Website Screenshot 854 |
855 |

Cheese Oven

856 |

857 | A vibrant and appetizing landing page for a pizza store, an interactive menu, online ordering, and special offers to entice customers. 858 |

859 | 860 | 861 |
862 | 863 | HTML 864 | HTML 865 | 866 | 867 | CSS 868 | CSS 869 | 870 | 871 | Bootstrap 872 | Bootstrap 873 | 874 | 875 | JavaScript 876 | JavaScript 877 | 878 |
879 | 880 | 881 | 891 |
892 |
893 | 894 | 895 | 896 |
897 | Portfolio Website Screenshot 898 |
899 |

Portfolio Website

900 |

901 | My portfolio website featuring my projects, skills, and journey. Built with HTML, CSS, and JavaScript for a modern, interactive experience. 902 |

903 | 904 | 905 |
906 | 907 | HTML 908 | HTML 909 | 910 | 911 | TailwindCSS 912 | Tailwindcss 913 | 914 | 915 | JavaScript 916 | JavaScript 917 | 918 | 919 | CSS 920 | CSS 921 | 922 | 923 | Framer Motion 924 | Framer Motion 925 | 926 |
927 | 928 | 929 | 939 |
940 |
941 | 942 |
943 |
944 |
945 | 946 | 947 |
948 |
949 |

Upcoming Projects

950 |

Some exciting ideas I'm currently working on.

951 |
952 | 953 |
954 | 955 |
956 |

Social Media App

957 |

A modern social media platform featuring user profiles, posts, real-time chat, notifications, and interactive feeds built with the MERN stack and Next.js.

958 | Coming Soon 959 |
960 | 961 | 962 |
963 |

School Management Dashboard

964 |

A MERN-based admin dashboard to manage students, attendance, teachers, and performance data with charts and analytics.

965 | Coming Soon 966 |
967 | 968 | 969 |
970 |

Rental Web Application

971 |

A property rental platform with user authentication, property listings, filtering, booking system, and admin control panel.

972 | Coming Soon 973 |
974 |
975 |
976 | 977 | 978 |
979 |
980 |
981 |

Get In Touch

982 |

Let's discuss your next project or just say hello!

983 |
984 | 985 |
986 | 987 |
988 |
989 |

Let's Connect

990 |

I'm always open to discussing new opportunities, interesting projects, or just having a chat about technology and development.

991 |
992 | 993 |
994 |
995 |
996 | 997 |
998 |
999 |

Email

1000 |

abhijeetbhale7@gmail.com

1001 |
1002 |
1003 | 1004 |
1005 |
1006 | 1007 |
1008 |
1009 |

Location

1010 |

Indore, Madhya Pradesh, India

1011 |
1012 |
1013 | 1014 |
1015 |
1016 | 1017 |
1018 |
1019 |

Response Time

1020 |

Within 24 hours

1021 |
1022 |
1023 |
1024 |
1025 | 1026 | 1027 |
1028 |
1029 |
1030 |
1031 | 1032 | 1040 |
1041 |
1042 | 1043 | 1051 |
1052 |
1053 | 1054 |
1055 | 1056 | 1064 |
1065 | 1066 |
1067 | 1068 | 1080 |
1081 | 1082 |
1083 | 1084 | 1092 |

1093 | 💡 Tip: Write a meaningful message with at least 3 words and 10 characters. Avoid random characters or excessive repetition. 1094 |

1095 |
1096 | 1097 | 1098 | 1099 | 1100 | 1110 |
1111 | 1112 | 1113 | 1116 |
1117 |
1118 |
1119 |
1120 | 1121 | 1122 |
1123 |
1124 | 1125 |

Let's connect and build something amazing!

1126 | 1127 | 1128 | 1129 |

abhijeetbhale7@gmail.com

1130 |
1131 | 1132 | 1133 | 1169 | 1170 |
1171 |
1172 | 1177 | abhijeetbhale7@gamil.com 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 |
1205 | 1211 |
1212 | 1213 | 1214 | 1215 | 1216 | --------------------------------------------------------------------------------