Merge branch 'sidebar'
This commit is contained in:
		
							
								
								
									
										14428
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14428
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -18,7 +18,8 @@ | ||||
|     "react-dom": "^18.3.1", | ||||
|     "react-icons": "^5.3.0", | ||||
|     "react-markdown": "^9.0.3", | ||||
|     "react-router-dom": "^7.1.1" | ||||
|     "react-router-dom": "^7.1.1", | ||||
|     "styled-component": "^2.8.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@eslint/js": "^9.9.0", | ||||
|  | ||||
| @ -4,6 +4,7 @@ import { Routes, Route } from 'react-router-dom' | ||||
| import './App.css' | ||||
| import Home from './pages/Home' | ||||
| import Navbar from './components/Navbar' | ||||
| import Sidebar from './components/Sidebar' | ||||
| import Footer from './components/Footer' | ||||
| import Experience from './pages/Experience' | ||||
| import Projects from './pages/Projects' | ||||
| @ -24,6 +25,11 @@ function App() { | ||||
|         <main className="bg-amber-50 px-10 dark:bg-gray-900"> | ||||
|           <section className="min-h-screen"> | ||||
|             <Navbar toggleDarkMode={toggleDarkMode} darkMode={darkMode} /> | ||||
|             <div className="md:flex md:flex-row md:h-full"> | ||||
|               <div className="mb-4 md:w-1/4 md:max-w-[260px] md:max-h-[900px] border-2 border-gray-300 dark:border-gray-700 rounded-lg shadow-sm"> | ||||
|                 <Sidebar /> | ||||
|               </div> | ||||
|               <div className="md:flex-1"> | ||||
|                 <Router> | ||||
|                   <Routes> | ||||
|                     <Route path="/" element={<Home />} /> | ||||
| @ -32,6 +38,9 @@ function App() { | ||||
|                     <Route path="/Interests" element={<Interests />} /> | ||||
|                   </Routes> | ||||
|                 </Router> | ||||
|               </div> | ||||
|               <div className="hidden md:block md:w-1/4 md:max-w-[260px] md:max-h-[900px]"></div> | ||||
|             </div> | ||||
|             <Footer /> | ||||
|           </section> | ||||
|         </main> | ||||
|  | ||||
| @ -29,7 +29,7 @@ const Footer = () => { | ||||
|  | ||||
|           <div className="flex items-center gap-2 text-xs"> | ||||
|             <Coffee size={14} className="inline-block" /> | ||||
|             <span>Powered by coffee and countless hours of debugging</span> | ||||
|             <span>Powered by coffee and Love</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| import { COLORS, SOCIALLINKS } from '../constants' | ||||
| import { Tooltip } from './Tooltip' | ||||
| import { COLORS } from '../constants' | ||||
|  | ||||
| const Introduction = () => { | ||||
|   const BoldStyle = 'text-blue-900 dark:text-blue-300 font-semibold' | ||||
| @ -35,24 +34,6 @@ const Introduction = () => { | ||||
|           and infrastructure automation to implementing robust testing frameworks. | ||||
|         </p> | ||||
|       </div> | ||||
|  | ||||
|       <div className="flex justify-center gap-8 py-3"> | ||||
|         {SOCIALLINKS.map((link, index) => ( | ||||
|           <div key={index} className="group relative"> | ||||
|             <Tooltip label={link.label} position="top"> | ||||
|               <a | ||||
|                 href={link.href} | ||||
|                 target="_blank" | ||||
|                 rel="noreferrer" | ||||
|                 className={`${COLORS.PRIMARY} ${COLORS.DARK_PRIMARY}  hover:text-sky-600 dark:hover:text-sky-500 transition-colors duration-200`} | ||||
|                 aria-label={link.label} | ||||
|               > | ||||
|                 {link.icon} | ||||
|               </a> | ||||
|             </Tooltip> | ||||
|           </div> | ||||
|         ))} | ||||
|       </div> | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
|  | ||||
							
								
								
									
										75
									
								
								frontend/src/components/Sidebar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								frontend/src/components/Sidebar.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| import { COLORS, SOCIALLINKS } from '../constants' | ||||
| import { Tooltip } from './Tooltip' | ||||
|  | ||||
| interface LinkProps { | ||||
|   href: string | ||||
|   children: React.ReactNode | ||||
|   icon: React.ReactNode | ||||
|   label: string | ||||
| } | ||||
|  | ||||
| const Link: React.FC<LinkProps> = ({ icon, href, children, label }) => { | ||||
|   return ( | ||||
|     <div className="transition-all duration-200 hover:translate-x-1"> | ||||
|       <div className="m-2 border border-gray-200 dark:border-gray-700 p-2 md:p-3 rounded-lg hover:shadow-md"> | ||||
|         <Tooltip label={label} position="top" additionalClass="md:hidden"> | ||||
|           <a | ||||
|             href={href} | ||||
|             target="_blank" | ||||
|             rel="noopener noreferrer" | ||||
|             className="flex items-center text-gray-700 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400" | ||||
|           > | ||||
|             {icon} | ||||
|             <span className="text-sm font-medium hidden md:inline">{children}</span> | ||||
|           </a> | ||||
|         </Tooltip> | ||||
|       </div> | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| const Sidebar = () => { | ||||
|   const SectionTitle = ({ children }: { children: React.ReactNode }) => ( | ||||
|     <h2 | ||||
|       className={`mt-4 mb-4 text-lg font-semibold ${COLORS.PRIMARY} ${COLORS.DARK_PRIMARY} hidden md:block`} | ||||
|     > | ||||
|       {children} | ||||
|     </h2> | ||||
|   ) | ||||
|  | ||||
|   return ( | ||||
|     <div | ||||
|       className={`grid grid-cols-4 md:grid-cols-1 p-2 md:p-6 max-w-xs mx-auto ${COLORS.PRIMARY} ${COLORS.DARK_PRIMARY} rounded-xl shadow-sm`} | ||||
|     > | ||||
|       <SectionTitle>Contact</SectionTitle> | ||||
|       {SOCIALLINKS.contact.map((link, index) => ( | ||||
|         <Link key={index} icon={link.icon} href={link.href} label={link.text}> | ||||
|           {link.text} | ||||
|         </Link> | ||||
|       ))} | ||||
|  | ||||
|       <SectionTitle>Connect</SectionTitle> | ||||
|       {SOCIALLINKS.connect.map((link, index) => ( | ||||
|         <Link key={index} icon={link.icon} href={link.href} label={link.text}> | ||||
|           {link.text} | ||||
|         </Link> | ||||
|       ))} | ||||
|  | ||||
|       <SectionTitle>Follow</SectionTitle> | ||||
|       {SOCIALLINKS.follow.map((link, index) => ( | ||||
|         <Link key={index} icon={link.icon} href={link.href} label={link.text}> | ||||
|           {link.text} | ||||
|         </Link> | ||||
|       ))} | ||||
|  | ||||
|       <SectionTitle>Achievements</SectionTitle> | ||||
|       {SOCIALLINKS.publications.map((link, index) => ( | ||||
|         <Link key={index} icon={link.icon} href={link.href} label={link.text}> | ||||
|           {link.text} | ||||
|         </Link> | ||||
|       ))} | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| export default Sidebar | ||||
| @ -1,6 +1,33 @@ | ||||
| import { COLORS, SKILLS } from '../constants' | ||||
| import pythonIcon from '../assets/python.svg' | ||||
| import robotIcon from '../assets/robotframework-svgrepo-com.svg' | ||||
| import goIcon from '../assets/go-original.svg' | ||||
| import reactIcon from '../assets/react.svg' | ||||
| import ansibleIcon from '../assets/ansible.svg' | ||||
| import terraformIcon from '../assets/terraform-icon.svg' | ||||
| import jenkinsIcon from '../assets/jenkins.svg' | ||||
| import gitIcon from '../assets/git-icon.svg' | ||||
| import dockerIcon from '../assets/docker-icon.svg' | ||||
| import kubernetesIcon from '../assets/kubernetes.svg' | ||||
| import prometheusIcon from '../assets/prometheus.svg' | ||||
| import grafanaIcon from '../assets/grafana.svg' | ||||
| import { COLORS } from '../constants' | ||||
|  | ||||
| const Skills = () => { | ||||
|   const skills = [ | ||||
|     { name: 'Python', icon: pythonIcon }, | ||||
|     { name: 'Golang', icon: goIcon }, | ||||
|     { name: 'React', icon: reactIcon }, | ||||
|     { name: 'Robot Framework', icon: robotIcon }, | ||||
|     { name: 'Ansible', icon: ansibleIcon }, | ||||
|     { name: 'Terraform', icon: terraformIcon }, | ||||
|     { name: 'Jenkins', icon: jenkinsIcon }, | ||||
|     { name: 'Git', icon: gitIcon }, | ||||
|     { name: 'Docker', icon: dockerIcon }, | ||||
|     { name: 'Kubernetes', icon: kubernetesIcon }, | ||||
|     { name: 'Prometheus', icon: prometheusIcon }, | ||||
|     { name: 'Grafana', icon: grafanaIcon }, | ||||
|   ] | ||||
|  | ||||
|   return ( | ||||
|     <div> | ||||
|       <h1 className={`text-2xl py-5 font-burtons ${COLORS.PRIMARY} ${COLORS.DARK_PRIMARY}`}> | ||||
| @ -9,7 +36,7 @@ const Skills = () => { | ||||
|       <div | ||||
|         className={`grid grid-cols-4 gap-6 text-md py-5 leading-8 ${COLORS.TEXT} ${COLORS.DARK_TEXT} mx-auto max-w-2xl md:text-xl`} | ||||
|       > | ||||
|         {SKILLS.map((skill) => ( | ||||
|         {skills.map((skill) => ( | ||||
|           <div key={skill.name} className="flex flex-col items-center"> | ||||
|             <img src={skill.icon} alt={skill.name} className="h-10 w-10" /> | ||||
|             <p className="mt-2 text-center">{skill.name}</p> | ||||
|  | ||||
| @ -2,9 +2,10 @@ export interface TooltipProps { | ||||
|   children: React.ReactNode | ||||
|   label: string | ||||
|   position: 'top' | 'bottom' | 'left' | 'right' | ||||
|   additionalClass?: string | ||||
| } | ||||
|  | ||||
| export const Tooltip: React.FC<TooltipProps> = ({ children, label, position }) => { | ||||
| export const Tooltip: React.FC<TooltipProps> = ({ children, label, position, additionalClass }) => { | ||||
|   const tooltipStyles = { | ||||
|     top: 'bottom-full left-1/2 -translate-x-1/2', | ||||
|     bottom: 'top-full left-1/2 -translate-x-1/2', | ||||
| @ -12,7 +13,7 @@ export const Tooltip: React.FC<TooltipProps> = ({ children, label, position }) = | ||||
|     right: 'left-full top-1/2 -translate-y-1/2', | ||||
|   } | ||||
|   const tooltipPosition: string = tooltipStyles[position] | ||||
|   const tooltipClass = `pointer-events-none absolute mt-2 whitespace-nowrap rounded bg-slate-800 px-2 py-1 text-xs text-slate-100 opacity-0 transition before:absolute before:left-1/2 before:top-full before:-translate-x-1/2 before:border-4 before:border-transparent before:border-t-slate-800 before:content-[''] group-hover:opacity-100 ${tooltipPosition}` | ||||
|   const tooltipClass = `pointer-events-none absolute mt-2 whitespace-nowrap rounded bg-slate-800 px-2 py-1 text-xs text-slate-100 opacity-0 transition before:absolute before:left-1/2 before:top-full before:-translate-x-1/2 before:border-4 before:border-transparent before:border-t-slate-800 before:content-[''] group-hover:opacity-100 ${tooltipPosition} ${additionalClass}` | ||||
|  | ||||
|   return ( | ||||
|     <div className="group relative"> | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| import { Linkedin, Github, Award, Link } from 'lucide-react' | ||||
| import { Aperture, Instagram, Mail, Globe, ScrollText } from 'lucide-react' | ||||
| import { Camera, Plane, Film, Server, Cpu, Trophy, Car, Gamepad2 } from 'lucide-react' | ||||
| import pythonIcon from './assets/python.svg' | ||||
| import robotIcon from './assets/robotframework-svgrepo-com.svg' | ||||
| import goIcon from './assets/go-original.svg' | ||||
| @ -86,23 +88,58 @@ export const PROJECTS = [ | ||||
|   }, | ||||
| ] | ||||
|  | ||||
| export const SOCIALLINKS = [ | ||||
| export const iconClass = 'text-blue-600 dark:text-blue-400 mr-3' | ||||
|  | ||||
| export const SOCIALLINKS = { | ||||
|   contact: [ | ||||
|     { | ||||
|     icon: <Linkedin size={32} />, | ||||
|       icon: <Mail size={20} className={iconClass} />, | ||||
|       href: 'mailto:taqitahmid@gmail.com', | ||||
|       text: 'Email Me', | ||||
|     }, | ||||
|     { | ||||
|       icon: <Globe size={20} className={iconClass} />, | ||||
|       href: 'https://portfolio.tahmidcloud.com/', | ||||
|       text: 'Website', | ||||
|     }, | ||||
|   ], | ||||
|   connect: [ | ||||
|     { | ||||
|       icon: <Linkedin size={20} className={iconClass} />, | ||||
|       href: 'https://www.linkedin.com/in/taqi-tahmid/', | ||||
|     label: 'LinkedIn', | ||||
|       text: 'LinkedIn', | ||||
|     }, | ||||
|     { | ||||
|     icon: <Github size={32} />, | ||||
|     href: 'https://github.com/TheTaqiTahmid', | ||||
|     label: 'GitHub', | ||||
|       icon: <Github size={20} className={iconClass} />, | ||||
|       href: 'https://github.com/theTaqiTahmid', | ||||
|       text: 'GitHub', | ||||
|     }, | ||||
|   ], | ||||
|   follow: [ | ||||
|     { | ||||
|       icon: <Aperture size={20} className={iconClass} />, | ||||
|       href: 'https://500px.com/p/taqi1203050?view=photos', | ||||
|       text: 'Photography', | ||||
|     }, | ||||
|     { | ||||
|     icon: <Award size={32} />, | ||||
|     href: 'https://ti-user-certificates.s3.amazonaws.com/e0df7fbf-a057-42af-8a1f-590912be5460/3da54db2-f994-4148-a0ca-705ae1d748cd-mohammad-taqi-tahmid-094cf8b4-0db8-4a9f-b787-b4efbb2a90fe-certificate.pdf', | ||||
|     label: 'CKA Certificate', | ||||
|       icon: <Instagram size={20} className={iconClass} />, | ||||
|       href: 'https://www.instagram.com/tahmidtaqi/', | ||||
|       text: 'Instagram', | ||||
|     }, | ||||
| ] | ||||
|   ], | ||||
|   publications: [ | ||||
|     { | ||||
|       icon: <Award size={20} className={iconClass} />, | ||||
|       href: 'https://www.credly.com/badges/abb049aa-d811-4954-a460-8c7351ceba3e/public_url', | ||||
|       text: 'CKA Certification', | ||||
|     }, | ||||
|     { | ||||
|       icon: <ScrollText size={20} className={iconClass} />, | ||||
|       href: 'https://scholar.google.fi/citations?user=w3BoP0AAAAAJ&hl=en', | ||||
|       text: 'Google Scholar', | ||||
|     }, | ||||
|   ], | ||||
| } | ||||
|  | ||||
| export const SKILLS = [ | ||||
|   { name: 'Python', icon: pythonIcon }, | ||||
| @ -119,6 +156,68 @@ export const SKILLS = [ | ||||
|   { name: 'Grafana', icon: grafanaIcon }, | ||||
| ] | ||||
|  | ||||
| export const INTERESTS = [ | ||||
|   { | ||||
|     title: 'Travelling', | ||||
|     icon: <Plane size={32} />, | ||||
|     description: | ||||
|       'Exploring new places, experiencing different cultures, and creating lasting memories through adventures around the world. From scenic landscapes to bustling cities, every journey is an opportunity to learn and grow.', | ||||
|   }, | ||||
|   { | ||||
|     title: 'Photography', | ||||
|     icon: <Camera size={32} />, | ||||
|     description: | ||||
|       'Capturing moments and perspectives through the lens. Particularly interested in landscape and street photography, always looking to improve composition skills and trying new techniques.', | ||||
|   }, | ||||
|   { | ||||
|     title: 'Movies & Shows', | ||||
|     icon: <Film size={32} />, | ||||
|     description: | ||||
|       'Passionate about cinema across various genres and cultures. Enjoy analyzing cinematography, storytelling techniques, and discovering hidden gems from different parts of the world.', | ||||
|   }, | ||||
|   { | ||||
|     title: 'Homelab', | ||||
|     icon: <Server size={32} />, | ||||
|     description: | ||||
|       'Managing a personal homelab setup for experimenting with self-hosted services, networking configurations, and learning about system administration in a hands-on environment.', | ||||
|   }, | ||||
|   { | ||||
|     title: 'New Technologies', | ||||
|     icon: <Cpu size={32} />, | ||||
|     description: | ||||
|       'Keeping up with the latest technological advancements, particularly in cloud computing, automation, and emerging DevOps tools. Enjoy experimenting with new frameworks and platforms.', | ||||
|   }, | ||||
|   { | ||||
|     title: 'Playing Video Games', | ||||
|     icon: <Gamepad2 size={32} />, | ||||
|     description: | ||||
|       'Enthusiastic gamer with a deep appreciation for interactive storytelling and virtual worlds. Enjoy exploring diverse genres from immersive RPGs to strategic multiplayer games.', | ||||
|   }, | ||||
|   { | ||||
|     title: 'Sports', | ||||
|     icon: <Trophy size={32} />, | ||||
|     description: 'Avid sports enthusiast following multiple disciplines:', | ||||
|     subInterests: [ | ||||
|       { | ||||
|         name: 'Football', | ||||
|         details: | ||||
|           'Following major leagues and international tournaments, appreciating the tactical aspects and team dynamics of the beautiful game.', | ||||
|       }, | ||||
|       { | ||||
|         name: 'Cricket', | ||||
|         details: | ||||
|           'Enjoying both test matches and limited-overs formats, following international competitions and analyzing game strategies.', | ||||
|       }, | ||||
|       { | ||||
|         name: 'Formula 1', | ||||
|         icon: <Car size={24} />, | ||||
|         details: | ||||
|           'Following the high-speed world of F1, keeping up with team developments, race strategies, and technical innovations in motorsport.', | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
| ] | ||||
|  | ||||
| export const EXPERIENCE = [ | ||||
|   { | ||||
|     title: 'Experienced Developer (DevOps)', | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { Building2, Calendar, GraduationCap, MapPin, Microscope, Wrench } from 'lucide-react' | ||||
| import { COLORS, EXPERIENCE, EDUCATION,  } from '../constants' | ||||
| import { COLORS, EXPERIENCE, EDUCATION } from '../constants' | ||||
|  | ||||
| const Experience = () => { | ||||
|   return ( | ||||
|  | ||||
| @ -1,69 +1,6 @@ | ||||
| import { Camera, Plane, Film, Server, Cpu, Trophy, Car, Gamepad2 } from 'lucide-react' | ||||
| import { COLORS } from '../constants' | ||||
| import { COLORS, INTERESTS } from '../constants' | ||||
|  | ||||
| const Interests = () => { | ||||
|   const interests = [ | ||||
|     { | ||||
|       title: 'Travelling', | ||||
|       icon: <Plane size={32} />, | ||||
|       description: | ||||
|         'Exploring new places, experiencing different cultures, and creating lasting memories through adventures around the world. From scenic landscapes to bustling cities, every journey is an opportunity to learn and grow.', | ||||
|     }, | ||||
|     { | ||||
|       title: 'Photography', | ||||
|       icon: <Camera size={32} />, | ||||
|       description: | ||||
|         'Capturing moments and perspectives through the lens. Particularly interested in landscape and street photography, always looking to improve composition skills and trying new techniques.', | ||||
|     }, | ||||
|     { | ||||
|       title: 'Movies & Shows', | ||||
|       icon: <Film size={32} />, | ||||
|       description: | ||||
|         'Passionate about cinema across various genres and cultures. Enjoy analyzing cinematography, storytelling techniques, and discovering hidden gems from different parts of the world.', | ||||
|     }, | ||||
|     { | ||||
|       title: 'Homelab', | ||||
|       icon: <Server size={32} />, | ||||
|       description: | ||||
|         'Managing a personal homelab setup for experimenting with self-hosted services, networking configurations, and learning about system administration in a hands-on environment.', | ||||
|     }, | ||||
|     { | ||||
|       title: 'New Technologies', | ||||
|       icon: <Cpu size={32} />, | ||||
|       description: | ||||
|         'Keeping up with the latest technological advancements, particularly in cloud computing, automation, and emerging DevOps tools. Enjoy experimenting with new frameworks and platforms.', | ||||
|     }, | ||||
|     { | ||||
|       title: 'Playing Video Games', | ||||
|       icon: <Gamepad2 size={32} />, | ||||
|       description: | ||||
|         'Enthusiastic gamer with a deep appreciation for interactive storytelling and virtual worlds. Enjoy exploring diverse genres from immersive RPGs to strategic multiplayer games.', | ||||
|     }, | ||||
|     { | ||||
|       title: 'Sports', | ||||
|       icon: <Trophy size={32} />, | ||||
|       description: 'Avid sports enthusiast following multiple disciplines:', | ||||
|       subInterests: [ | ||||
|         { | ||||
|           name: 'Football', | ||||
|           details: | ||||
|             'Following major leagues and international tournaments, appreciating the tactical aspects and team dynamics of the beautiful game.', | ||||
|         }, | ||||
|         { | ||||
|           name: 'Cricket', | ||||
|           details: | ||||
|             'Enjoying both test matches and limited-overs formats, following international competitions and analyzing game strategies.', | ||||
|         }, | ||||
|         { | ||||
|           name: 'Formula 1', | ||||
|           icon: <Car size={24} />, | ||||
|           details: | ||||
|             'Following the high-speed world of F1, keeping up with team developments, race strategies, and technical innovations in motorsport.', | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|   ] | ||||
|  | ||||
|   return ( | ||||
|     <div className="p-4 max-w-4xl mx-auto"> | ||||
|       <h1 | ||||
| @ -73,7 +10,7 @@ const Interests = () => { | ||||
|       </h1> | ||||
|  | ||||
|       <div className="grid gap-6 md:grid-cols-2"> | ||||
|         {interests.map((interest, index) => ( | ||||
|         {INTERESTS.map((interest, index) => ( | ||||
|           <div | ||||
|             key={index} | ||||
|             className={`group p-6 rounded-lg border-2 border-gray-300 dark:border-gray-700 hover:shadow-lg transition-all duration-300 ${ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user