formatted with prettier

This commit is contained in:
2025-04-10 20:50:21 +03:00
parent d3c744fec7
commit 6944751b82
18 changed files with 473 additions and 469 deletions

View File

@ -1,17 +0,0 @@
import { Link } from "react-router-dom";
export const BlogCard = ({ title, description, slug, date }) => {
return (
<Link to={`/blog/${slug}`} className="no-underline">
<div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm hover:shadow-lg transition-shadow duration-200">
<div className="space-y-2">
<h3 className="text-2xl font-semibold tracking-tight">{title}</h3>
<div>
<p className="text-sm text-gray-500">{date}</p>
<p className="mt-2 text-gray-600">{description}</p>
</div>
</div>
</div>
</Link>
);
};

View File

@ -1,17 +0,0 @@
import { BlogCard } from "./BlogCard";
export const BlogList = ({ posts }) => {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
{posts.map((post) => (
<BlogCard
key={post.slug}
title={post.title}
description={post.description}
slug={post.slug}
date={post.date}
/>
))}
</div>
);
};

View File

@ -1,45 +0,0 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import ReactMarkdown from "react-markdown";
export const BlogPost = () => {
const { slug } = useParams();
const [content, setContent] = useState("");
const [metadata, setMetadata] = useState(null);
useEffect(() => {
const fetchPost = async () => {
try {
const post = await import(`../assets/blogs/${slug}.md`);
const response = await fetch(post.default);
const text = await response.text();
setContent(text);
// const meta = await import(`../content/metadata/${slug}.json`);
// setMetadata(meta.default);
} catch (error) {
console.error("Error loading blog post:", error);
}
};
fetchPost();
}, [slug]);
if (!content) {
return (
<div className="flex justify-center items-center min-h-screen">
<p className="text-gray-600">Loading...</p>
</div>
);
}
return (
<article className="max-w-3xl mx-auto p-6">
{/* <h1 className="text-4xl font-bold mb-4">{metadata.title}</h1>
<div className="text-gray-500 mb-8">{metadata.date}</div> */}
<div className="prose prose-lg">
<ReactMarkdown>{content}</ReactMarkdown>
</div>
</article>
);
};

View File

@ -1,7 +1,7 @@
import { Server, Coffee } from "lucide-react";
import { Server, Coffee } from 'lucide-react'
const Footer = () => {
const currentYear = new Date().getFullYear();
const currentYear = new Date().getFullYear()
return (
<footer className="mt-16 py-6 border-t border-gray-200 dark:border-gray-800">
@ -11,15 +11,15 @@ const Footer = () => {
<Server size={16} className="inline-block" />
<span>Self-hosted on my homelab Kubernetes cluster</span>
</div>
<div className="flex flex-wrap justify-center gap-x-4 gap-y-2 text-center">
<span>© {currentYear} Taqi Tahmid</span>
<span></span>
<span>Built with React & Tailwind CSS</span>
<span></span>
<a
href="https://github.com/TheTaqiTahmid/my-portfolio.git"
target="_blank"
<a
href="https://github.com/TheTaqiTahmid/my-portfolio.git"
target="_blank"
rel="noreferrer"
className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
>
@ -29,14 +29,12 @@ 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 countless hours of debugging</span>
</div>
</div>
</div>
</footer>
);
};
)
}
export default Footer;
export default Footer

View File

@ -1,75 +1,79 @@
import { Linkedin, Github, Award } from "lucide-react";
import { COLORS } from "../constants";
import { Linkedin, Github, Award } from 'lucide-react'
import { COLORS } from '../constants'
const Introduction = () => {
const BoldStyle = "text-blue-900 dark:text-blue-300 font-semibold";
const BoldStyle = 'text-blue-900 dark:text-blue-300 font-semibold'
const socialLinks = [
{
icon: <Linkedin size={32} />,
href: "https://www.linkedin.com/in/taqi-tahmid/",
label: "LinkedIn"
href: 'https://www.linkedin.com/in/taqi-tahmid/',
label: 'LinkedIn',
},
{
icon: <Github size={32} />,
href: "https://github.com/TheTaqiTahmid",
label: "GitHub"
href: 'https://github.com/TheTaqiTahmid',
label: 'GitHub',
},
{
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"
}
];
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',
},
]
return (
<div className="text-center p-4 max-w-4xl mx-auto">
<h1 className={`text-5xl py-2 ${COLORS.PRIMARY} ${COLORS.DARK_PRIMARY} font-medium font-mono tracking-wide`}>
<h1
className={`text-5xl py-2 ${COLORS.PRIMARY} ${COLORS.DARK_PRIMARY} font-medium font-mono tracking-wide`}
>
Taqi Tahmid
</h1>
<h2 className={`text-2xl py-2 font-burtons ${COLORS.PRIMARY} ${COLORS.DARK_PRIMARY}`}>
Test Automation and DevOps Engineer
</h2>
<div className={`text-md py-5 ${COLORS.TEXT} ${COLORS.DARK_TEXT} leading-8 md:text-xl space-y-4`}>
<div
className={`text-md py-5 ${COLORS.TEXT} ${COLORS.DARK_TEXT} leading-8 md:text-xl space-y-4`}
>
<p>
I am a <span className={BoldStyle}>DevOps</span> and{" "}
<span className={BoldStyle}>Test Automation</span> engineer with a{" "}
<span className={BoldStyle}>certified Kubernetes Administrator (CKA)</span> certification,
specializing in managing Kubernetes clusters and cloud infrastructure.
Currently working at Ericsson in Finland as a DevOps Engineer.
I am a <span className={BoldStyle}>DevOps</span> and{' '}
<span className={BoldStyle}>Test Automation</span> engineer with a{' '}
<span className={BoldStyle}>certified Kubernetes Administrator (CKA)</span> certification,
specializing in managing Kubernetes clusters and cloud infrastructure. Currently working
at Ericsson in Finland as a DevOps Engineer.
</p>
<p>
I bring four years of industry experience in designing CI/CD pipelines
and test automation for diverse applications and architectures. I hold a Bachelor's
degree from Khulna University of Engineering & Technology (KUET) and a Master's
degree from Tampere University. My expertise spans across the entire DevOps lifecycle,
from cluster management and infrastructure automation to implementing robust testing frameworks.
I bring four years of industry experience in designing CI/CD pipelines and test automation
for diverse applications and architectures. I hold a Bachelor's degree from Khulna
University of Engineering & Technology (KUET) and a Master's degree from Tampere
University. My expertise spans across the entire DevOps lifecycle, from cluster management
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">
<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>
<span className="pointer-events-none absolute -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-800 px-2 py-1 text-sm 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">
{link.label}
</span>
</div>
<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>
<span className="pointer-events-none absolute -top-8 left-1/2 -translate-x-1/2 whitespace-nowrap rounded bg-slate-800 px-2 py-1 text-sm 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">
{link.label}
</span>
</div>
))}
</div>
</div>
);
};
)
}
export default Introduction;
export default Introduction

View File

@ -1,109 +1,120 @@
import React, { useEffect, useState, useRef } from 'react';
import { Menu, Sun, Moon, FileText, Mail, Check, Copy } from "lucide-react";
import { COLORS, EMAIL, RESUME } from '../constants';
import React, { useEffect, useState, useRef } from 'react'
import { Menu, Sun, Moon, FileText, Mail, Check, Copy } from 'lucide-react'
import { COLORS, EMAIL, RESUME } from '../constants'
interface NavProps {
darkMode: boolean;
toggleDarkMode: () => void;
darkMode: boolean
toggleDarkMode: () => void
}
const Navbar: React.FC<NavProps> = ({toggleDarkMode, darkMode}) => {
const [copied, setCopied] = useState(false);
const [isMenuOpen, setIsMenuOpen] = useState(false);
const menuRef = useRef<HTMLDivElement>(null);
const Navbar: React.FC<NavProps> = ({ toggleDarkMode, darkMode }) => {
const [copied, setCopied] = useState(false)
const [isMenuOpen, setIsMenuOpen] = useState(false)
const menuRef = useRef<HTMLDivElement>(null)
const handleCopyEmail = async () => {
try {
await navigator.clipboard.writeText(EMAIL);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
await navigator.clipboard.writeText(EMAIL)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
} catch (err) {
console.error('Failed to copy email');
console.error('Failed to copy email', err)
}
};
}
useEffect(() => {
localStorage.setItem('DARK_MODE', String(darkMode))
},[darkMode])
}, [darkMode])
const menuItem = [
{title: 'Home', href: '/'},
{title: 'Experience', href: '/experience'},
{title: 'Projects', href: '/projects'},
{title: 'Interests', href: '/interests'},
{ title: 'Home', href: '/' },
{ title: 'Experience', href: '/experience' },
{ title: 'Projects', href: '/projects' },
{ title: 'Interests', href: '/interests' },
]
return (
<div className="w-full flex justify-center">
<nav className="py-5 mb-6 flex justify-between dark:text-white w-full max-w-5xl px-4">
<button
onClick={handleCopyEmail}
className="flex items-center space-x-2 hover:bg-gray-100 dark:hover:bg-gray-800 px-3 py-2 rounded-lg transition-colors duration-200 group relative"
<button
onClick={handleCopyEmail}
className="flex items-center space-x-2 hover:bg-gray-100 dark:hover:bg-gray-800 px-3 py-2 rounded-lg transition-colors duration-200 group relative"
>
<Mail size={25} className={`${COLORS.DARK_PRIMARY}`} />
<span>Email</span>
{copied ? (
<Check size={16} className="text-green-500" />
) : (
<Copy
size={16}
className="opacity-0 group-hover:opacity-100 transition-opacity duration-200"
/>
)}
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/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">
{copied ? 'Copied!' : 'Click to copy'}
</span>
</button>
<ul className="flex items-center">
<li
className="transition ease-in-out delay-50 duration-100 cursor-pointer"
onClick={toggleDarkMode}
>
<Mail size={25} className={`${COLORS.DARK_PRIMARY}`} />
<span>Email</span>
{copied ? (
<Check size={16} className="text-green-500" />
) : (
<Copy size={16} className="opacity-0 group-hover:opacity-100 transition-opacity duration-200" />
)}
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/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">
{copied ? 'Copied!' : 'Click to copy'}
</span>
</button>
<div className="group relative">
{darkMode ? (
<Sun className="text-amber-400 hover:scale-110" size={30} />
) : (
<Moon size={24} />
)}
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/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">
{darkMode ? 'Light Mode' : 'Dark Mode'}
</span>
</div>
</li>
<li className="transition ease-in-out delay-50 duration-100">
<div className="group relative">
<a
className="text-white p-2 ml-8 inline-flex"
href={RESUME}
target="_blank"
rel="noreferrer"
>
<FileText className="hover:scale-110 text-gray-800 dark:text-white" size={30} />
</a>
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/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">
Resume
</span>
</div>
</li>
<li className="p-2 ml-5 cursor-pointer">
<div ref={menuRef} className="group relative">
<button onClick={() => setIsMenuOpen(!isMenuOpen)} className="focus:outline-none">
<Menu size={24} />
</button>
<ul className="flex items-center">
<li className="transition ease-in-out delay-50 duration-100 cursor-pointer"
onClick={toggleDarkMode}>
<div className="group relative">
{darkMode ? <Sun className='text-amber-400 hover:scale-110' size={30} /> : <Moon size={24} />}
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/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">
{darkMode ? "Light Mode": "Dark Mode"}
</span>
</div>
</li>
<li className="transition ease-in-out delay-50 duration-100">
<div className="group relative">
<a className="text-white p-2 ml-8 inline-flex"
href={RESUME}
target="_blank"
rel="noreferrer">
<FileText className="hover:scale-110 text-gray-800 dark:text-white" size={30} />
</a>
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/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">
Resume
</span>
{/* Dropdown Menu */}
{isMenuOpen && (
<div className="absolute right-0 mt-3 w-36 rounded-md shadow-lg bg-amber-50 dark:bg-gray-800 ring-1 ring-black ring-opacity-5">
<div className="py-1" role="menu" aria-orientation="vertical">
{menuItem.map((item) => (
<a
key={item.title}
href={item.href}
className="block px-4 py-2 text-sm text-gray-00 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors duration-150"
role="menuitem"
>
{item.title}
</a>
))}
</div>
</li>
<li className="p-2 ml-5 cursor-pointer">
<div ref={menuRef} className="group relative">
<button onClick={() => setIsMenuOpen(!isMenuOpen)} className='focus:outline-none'>
<Menu size={24}/>
</button>
{/* Dropdown Menu */}
{isMenuOpen && (
<div className="absolute right-0 mt-3 w-36 rounded-md shadow-lg bg-amber-50 dark:bg-gray-800 ring-1 ring-black ring-opacity-5">
<div className="py-1" role="menu" aria-orientation="vertical">
{menuItem.map((item) => (
<a
key={item.title}
href={item.href}
className="block px-4 py-2 text-sm text-gray-00 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors duration-150"
role='menuitem'
>
{item.title}
</a>
))}
</div>
</div>
)}
</div>
</li>
</ul>
)}
</div>
</li>
</ul>
</nav>
</div>
);
};
)
}
export default Navbar;
export default Navbar

View File

@ -1,12 +1,14 @@
import taqimugshot from "../../src/assets/PhotoRoom_20201011_002118.jpg";
import taqimugshot from '../../src/assets/PhotoRoom_20201011_002118.jpg'
const Photo = () => {
return (
<div className="py-3">
<img className="relative mx-auto rounded-full w-80 h-80 object-cover"
src={taqimugshot}
alt="mugshot"/>
</div>
<img
className="relative mx-auto rounded-full w-80 h-80 object-cover"
src={taqimugshot}
alt="mugshot"
/>
</div>
)
}
export default Photo
export default Photo

View File

@ -1,39 +1,41 @@
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";
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 },
];
{ 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}`}>
Tools and Languages
</h1>
<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`}>
<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) => (
<div key={skill.name} className="flex flex-col items-center">
<img src={skill.icon} alt={skill.name} className="h-10 w-10" />
@ -42,7 +44,7 @@ const Skills = () => {
))}
</div>
</div>
);
};
)
}
export default Skills;
export default Skills