first commit
This commit is contained in:
26
pages/_app.tsx
Normal file
26
pages/_app.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useEffect } from 'react';
|
||||
import type { AppProps } from 'next/app';
|
||||
|
||||
import Layout from '@/components/Layout';
|
||||
import Head from '@/components/Head';
|
||||
|
||||
import '@/styles/globals.css';
|
||||
import '@/styles/themes.css';
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
useEffect(() => {
|
||||
const theme = localStorage.getItem('theme');
|
||||
if (theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Head title={`Ahmed Galadima | ${pageProps.title}`} />
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
124
pages/about.tsx
Normal file
124
pages/about.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import styles from '@/styles/AboutPage.module.css';
|
||||
import Link from 'next/link';
|
||||
import { FaTools, FaRocket, FaCertificate, FaCodeBranch } from 'react-icons/fa';
|
||||
|
||||
const AboutPage = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<header className={styles.header}>
|
||||
<h1 className={styles.title}>Ahmed Galadima</h1>
|
||||
<div className={styles.subtitle}>Senior QA Engineer & Automation Consultant</div>
|
||||
<p className={styles.tagline}>Turning quality assurance into competitive advantage</p>
|
||||
</header>
|
||||
|
||||
<div className={styles.aboutContent}>
|
||||
<section className={styles.section}>
|
||||
<div className={styles.highlightCard}>
|
||||
<h2 className={styles.sectionTitle}>Value Proposition</h2>
|
||||
<p className={styles.paragraph}>
|
||||
I help startups and tech teams <span className={styles.highlight}>ship flawless software 30% faster </span>
|
||||
through strategic test automation and CI/CD optimization. Proven track record of reducing post-launch
|
||||
defects by 70%+ and QA costs by 40%+.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}><FaRocket className={styles.icon} /> Key Achievements</h2>
|
||||
<div className={styles.grid}>
|
||||
<div className={styles.card}>
|
||||
<h3>Process Automation</h3>
|
||||
<ul className={styles.list}>
|
||||
<li>Reduced regression testing time by 65% through Selenium frameworks</li>
|
||||
<li>Implemented CI/CD pipelines cutting release cycles from 4 weeks to 10 days</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br></br>
|
||||
<div className={styles.card}>
|
||||
<h3>Client Impact</h3>
|
||||
<ul className={styles.list}>
|
||||
<li>$50K+ saved in remediation costs for fintech clients</li>
|
||||
<li>Zero critical bugs in 5+ MVP launches</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}><FaTools className={styles.icon} /> Technical Arsenal</h2>
|
||||
<div className={styles.techGrid}>
|
||||
<div className={styles.techItem}>
|
||||
<FaCodeBranch className={styles.techIcon} />
|
||||
<div>
|
||||
<h3>Automation</h3>
|
||||
<p>Selenium · Cypress · Postman · JMeter</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.techItem}>
|
||||
<FaCertificate className={styles.techIcon} />
|
||||
<div>
|
||||
<h3>CI/CD & DevOps</h3>
|
||||
<p>Jenkins · Docker · GitLab CI · Kubernetes</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}>Client Success Stories</h2>
|
||||
<div className={styles.caseStudy}>
|
||||
<h3>HealthTech Startup</h3>
|
||||
<div className={styles.challenge}>
|
||||
<span>Challenge:</span> MVP launch blocked by 100+ critical bugs
|
||||
</div>
|
||||
<div className={styles.solution}>
|
||||
<span>Solution:</span> 3-day QA audit + automated regression suite
|
||||
</div>
|
||||
<div className={styles.outcome}>
|
||||
<span>Outcome:</span> Zero critical bugs at launch · $500K seed funding secured
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}>Credentials</h2>
|
||||
<div className={styles.credentials}>
|
||||
<div className={styles.badge}>
|
||||
<FaCertificate className={styles.badgeIcon} />
|
||||
ISTQB Advanced
|
||||
</div>
|
||||
<div className={styles.badge}>
|
||||
<FaCertificate className={styles.badgeIcon} />
|
||||
Certified ScrumMaster
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}>Testimonials</h2>
|
||||
<blockquote className={styles.testimonial}>
|
||||
Ahmed's automation framework became our secret weapon for scaling.
|
||||
Cut our testing costs by 60% while improving coverage.
|
||||
<cite>- CTO, SaaS Platform</cite>
|
||||
</blockquote>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div className={styles.ctaSection}>
|
||||
<Link href={"./contact"} className={styles.ctaButton}>
|
||||
Let's Automate Your Quality
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: { title: 'Expert QA Engineering Services' },
|
||||
};
|
||||
}
|
||||
|
||||
export default AboutPage;
|
||||
58
pages/articles.tsx
Normal file
58
pages/articles.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import ArticleCard from '@/components/ArticleCard';
|
||||
|
||||
import { Article } from '@/types';
|
||||
|
||||
import styles from '@/styles/ArticlesPage.module.css';
|
||||
|
||||
interface ArticlesPageProps {
|
||||
articles: Article[];
|
||||
}
|
||||
|
||||
const ArticlesPage = ({ articles }: ArticlesPageProps) => {
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
<h1 className={styles.pageTitle}>My Articles</h1>
|
||||
<p className={styles.pageSubtitle}>
|
||||
Recent posts from{' '}
|
||||
<a
|
||||
href="https://dev.to/galads"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
className={styles.underline}
|
||||
>
|
||||
dev.to
|
||||
</a>{' '}
|
||||
where I share insights and tutorials about web development.
|
||||
</p>
|
||||
<div className={styles.container}>
|
||||
{articles.length > 0 ? (
|
||||
articles.map((article) => (
|
||||
<ArticleCard key={article.id} article={article} />
|
||||
))
|
||||
) :(
|
||||
<p>No articles available at the moment.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getStaticProps() {
|
||||
const res = await fetch(
|
||||
'https://dev.to/api/articles/me/published?per_page=6',
|
||||
{
|
||||
headers: {
|
||||
'api-key': process.env.DEV_TO_API_KEY!,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
return {
|
||||
props: { title: 'Articles', articles: data },
|
||||
revalidate: 60,
|
||||
};
|
||||
}
|
||||
|
||||
export default ArticlesPage;
|
||||
28
pages/contact.tsx
Normal file
28
pages/contact.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import ContactCode from '@/components/ContactCode';
|
||||
|
||||
import styles from '@/styles/ContactPage.module.css';
|
||||
|
||||
const ContactPage = () => {
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
<h1 className={styles.pageTitle}>Contact Me</h1>
|
||||
<p className={styles.pageSubtitle}>
|
||||
Feel free to reach out to me through any of the social platforms below.
|
||||
I'm always open to new opportunities and connections.
|
||||
</p>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.contactContainer}>
|
||||
<ContactCode />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: { title: 'Contact' },
|
||||
};
|
||||
}
|
||||
|
||||
export default ContactPage;
|
||||
99
pages/github.tsx
Normal file
99
pages/github.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import Image from 'next/image';
|
||||
import GitHubCalendar from 'react-github-calendar';
|
||||
import { VscRepo, VscPerson } from 'react-icons/vsc';
|
||||
|
||||
import RepoCard from '@/components/RepoCard';
|
||||
import { Repo, User } from '@/types';
|
||||
|
||||
import styles from '@/styles/GithubPage.module.css';
|
||||
|
||||
interface GithubPageProps {
|
||||
repos: Repo[];
|
||||
user: User;
|
||||
}
|
||||
|
||||
const GithubPage = ({ repos, user }: GithubPageProps) => {
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
<div className={styles.pageHeading}>
|
||||
<h1 className={styles.pageTitle}>GitHub</h1>
|
||||
<p className={styles.pageSubtitle}>
|
||||
Browse through my GitHub repositories and see what I've been
|
||||
working on. These are some of my public repositories showcasing
|
||||
various projects and skills.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.githubPage}>
|
||||
<div className={styles.profileSection}>
|
||||
<div className={styles.profileInfo}>
|
||||
<Image
|
||||
src={user.avatar_url}
|
||||
className={styles.avatar}
|
||||
alt={user.login}
|
||||
width={100}
|
||||
height={100}
|
||||
priority
|
||||
/>
|
||||
<div className={styles.userInfo}>
|
||||
<h2 className={styles.username}>{user.login}</h2>
|
||||
<div className={styles.stats}>
|
||||
<div className={styles.statItem}>
|
||||
<VscRepo className={styles.statIcon} />
|
||||
<span>{user.public_repos} repositories</span>
|
||||
</div>
|
||||
<div className={styles.statItem}>
|
||||
<VscPerson className={styles.statIcon} />
|
||||
<span>{user.followers} followers</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.sectionHeader}>
|
||||
<h3 className={styles.sectionTitle}>Popular Repositories</h3>
|
||||
</div>
|
||||
<div className={styles.reposContainer}>
|
||||
{repos.map((repo) => (
|
||||
<RepoCard key={repo.id} repo={repo} />
|
||||
))}
|
||||
</div>
|
||||
<div className={styles.contributions}>
|
||||
<GitHubCalendar
|
||||
username={process.env.NEXT_PUBLIC_GITHUB_USERNAME!}
|
||||
hideColorLegend
|
||||
hideMonthLabels
|
||||
colorScheme="dark"
|
||||
theme={{
|
||||
dark: ['#161B22', '#0e4429', '#006d32', '#26a641', '#39d353'],
|
||||
light: ['#161B22', '#0e4429', '#006d32', '#26a641', '#39d353'],
|
||||
}}
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getStaticProps() {
|
||||
const userRes = await fetch(
|
||||
`https://api.github.com/users/${process.env.NEXT_PUBLIC_GITHUB_USERNAME}`
|
||||
);
|
||||
const user = await userRes.json();
|
||||
|
||||
const repoRes = await fetch(
|
||||
`https://api.github.com/users/${process.env.NEXT_PUBLIC_GITHUB_USERNAME}/repos?sort=pushed&per_page=6`
|
||||
);
|
||||
const repos = await repoRes.json();
|
||||
|
||||
return {
|
||||
props: { title: 'GitHub', repos, user },
|
||||
revalidate: 600,
|
||||
};
|
||||
}
|
||||
|
||||
export default GithubPage;
|
||||
137
pages/index.tsx
Normal file
137
pages/index.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { VscArrowRight } from 'react-icons/vsc';
|
||||
|
||||
import styles from '@/styles/HomePage.module.css';
|
||||
|
||||
export default function HomePage() {
|
||||
const [activeLineIndex, setActiveLineIndex] = useState(0);
|
||||
|
||||
const codeLines = [
|
||||
{ code: 'const HomePage = () => {', type: 'function' },
|
||||
{
|
||||
code: ' const [isLoaded, setIsLoaded] = useState(true);',
|
||||
type: 'variable',
|
||||
},
|
||||
{ code: ' const developerInfo = {', type: 'variable' },
|
||||
{ code: " name: 'Ahmed Galadima',", type: 'array-item' },
|
||||
{ code: " role: 'Senior QA Engineer & Consultant',", type: 'array-item' },
|
||||
{ code: " bio: 'Dynamic Senior QA Engineer & Consultant with over 10+ years of expertise'", type: 'array-item' },
|
||||
{ code: ' };', type: 'array-end' },
|
||||
{ code: '', type: 'blank' },
|
||||
{ code: ' useEffect(() => {', type: 'nested-function' },
|
||||
{
|
||||
code: ' document.title = `${developerInfo.name} | Portfolio`;',
|
||||
type: 'return',
|
||||
},
|
||||
{ code: ' setIsLoaded(true);', type: 'function-call' },
|
||||
{ code: ' }, []);', type: 'close' },
|
||||
{ code: '', type: 'blank' },
|
||||
{ code: ' return (', type: 'return-object' },
|
||||
{ code: ' <main className="hero-container">', type: 'object-method' },
|
||||
{ code: ' <h1>{developerInfo.name}</h1>', type: 'object-method' },
|
||||
{ code: ' <p>{developerInfo.role}</p>', type: 'object-method' },
|
||||
{ code: ' <div className="cta">', type: 'object-method' },
|
||||
{
|
||||
code: ' <Link href="/projects">View Projects</Link>',
|
||||
type: 'object-method',
|
||||
},
|
||||
{ code: ' </div>', type: 'object-method' },
|
||||
{ code: ' </main>', type: 'object-method' },
|
||||
{ code: ' );', type: 'close' },
|
||||
{ code: '};', type: 'close-function' },
|
||||
{ code: '', type: 'blank' },
|
||||
{ code: 'export default HomePage;', type: 'function-call' },
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setActiveLineIndex((prev) => (prev + 1) % codeLines.length);
|
||||
}, 2000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [codeLines.length]);
|
||||
|
||||
return (
|
||||
<div className={styles.heroLayout}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.codeSection}>
|
||||
<div className={styles.codeContainer}>
|
||||
<div className={styles.editorContent}>
|
||||
<div className={styles.lineNumbers}>
|
||||
{codeLines.map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`${styles.lineNumber} ${
|
||||
index === activeLineIndex ? styles.activeLine : ''
|
||||
}`}
|
||||
>
|
||||
{index + 1}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className={styles.codeEditor}>
|
||||
{codeLines.map((line, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`${styles.codeLine} ${styles[line.type]} ${
|
||||
index === activeLineIndex ? styles.highlightedLine : ''
|
||||
}`}
|
||||
>
|
||||
{line.code}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className={styles.overlayGlow}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.infoSection}>
|
||||
<h1 className={styles.developerName}>
|
||||
Ahmed <span className={styles.accentText}>Galadima</span>
|
||||
</h1>
|
||||
|
||||
<div className={styles.developerRole}>Senior QA Engineer & Consultant</div>
|
||||
|
||||
<p className={styles.bio}>
|
||||
Dynamic Senior QA Engineer & Consultant with 10+ years of expertise in delivering 30% faster software releases and
|
||||
40%+ cost savings for startups and enterprises. Specialize in transforming chaotic workflows into streamlined,
|
||||
automation-driven processes that ensure client products exceed market standards.
|
||||
</p>
|
||||
|
||||
<div className={styles.actionLinks}>
|
||||
<Link href="/projects" className={styles.primaryLink}>
|
||||
View Projects <VscArrowRight />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.decorElements}>
|
||||
<div className={styles.codeFlare}></div>
|
||||
<div className={styles.gridLines}></div>
|
||||
<div className={styles.codeBlock1}>{'{'}</div>
|
||||
<div className={styles.codeBlock2}>{'}'}</div>
|
||||
<div className={styles.codeBlock3}>{'<>'}</div>
|
||||
<div className={styles.codeBlock4}>{'/>'}</div>
|
||||
<div className={styles.orb1}></div>
|
||||
<div className={styles.orb2}></div>
|
||||
<div className={styles.orb3}></div>
|
||||
<div className={styles.codeSymbol1}>{'()'}</div>
|
||||
<div className={styles.codeSymbol2}>{'[]'}</div>
|
||||
<div className={styles.codeSymbol3}>{'=>'}</div>
|
||||
<div className={styles.dotPattern}></div>
|
||||
<div className={styles.mobileAccent}></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: { title: 'Home' },
|
||||
};
|
||||
}
|
||||
31
pages/projects.tsx
Normal file
31
pages/projects.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import ProjectCard from '@/components/ProjectCard';
|
||||
import { projects } from '@/data/projects';
|
||||
|
||||
import styles from '@/styles/ProjectsPage.module.css';
|
||||
|
||||
const ProjectsPage = () => {
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
<h1 className={styles.pageTitle}>Software Development and QA Projects</h1>
|
||||
<p className={styles.pageSubtitle}>
|
||||
Here's a collection of my recent work. These projects showcase my
|
||||
skills in web development, design, and problem-solving.
|
||||
</p>
|
||||
|
||||
<div className={styles.container}>
|
||||
{projects.map((project) => (
|
||||
<ProjectCard key={project.slug} project={project} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: { title: 'Projects' },
|
||||
};
|
||||
}
|
||||
|
||||
export default ProjectsPage;
|
||||
56
pages/settings.tsx
Normal file
56
pages/settings.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import ThemeInfo from '@/components/ThemeInfo';
|
||||
|
||||
import styles from '@/styles/SettingsPage.module.css';
|
||||
|
||||
const SettingsPage = () => {
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
<div className={styles.container}>
|
||||
<ThemeInfo
|
||||
name="GitHub Dark"
|
||||
icon="/themes/github-dark.png"
|
||||
publisher="GitHub"
|
||||
theme="github-dark"
|
||||
/>
|
||||
<ThemeInfo
|
||||
name="Dracula"
|
||||
icon="/themes/dracula.png"
|
||||
publisher="Dracula Theme"
|
||||
theme="dracula"
|
||||
/>
|
||||
<ThemeInfo
|
||||
name="Ayu Dark"
|
||||
icon="/themes/ayu.png"
|
||||
publisher="teabyii"
|
||||
theme="ayu-dark"
|
||||
/>
|
||||
<ThemeInfo
|
||||
name="Ayu Mirage"
|
||||
icon="/themes/ayu.png"
|
||||
publisher="teabyii"
|
||||
theme="ayu-mirage"
|
||||
/>
|
||||
<ThemeInfo
|
||||
name="Nord"
|
||||
icon="/themes/nord.png"
|
||||
publisher="arcticicestudio"
|
||||
theme="nord"
|
||||
/>
|
||||
<ThemeInfo
|
||||
name="Night Owl"
|
||||
icon="/themes/night-owl.png"
|
||||
publisher="sarah.drasner"
|
||||
theme="night-owl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: { title: 'Settings' },
|
||||
};
|
||||
}
|
||||
|
||||
export default SettingsPage;
|
||||
Reference in New Issue
Block a user