Skip to content

Commit

Permalink
added light/dark mode and improved ui (#738)
Browse files Browse the repository at this point in the history
* added dark/light theme mode

* updated icons and add cache for projects and blogs api fetch

* improved some ui issue for theme

* improved schemas

* fixed default theme

* improved the ui and fixed image issue

* updated discord link
  • Loading branch information
muhammad-fiaz authored Dec 30, 2024
1 parent 5011cb8 commit 6a59223
Show file tree
Hide file tree
Showing 36 changed files with 695 additions and 591 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
![GitHub stars](https://img.shields.io/github/stars/muhammad-fiaz/portfolio.svg?style=social&label=Stars)

[![Follow me on GitHub](https://img.shields.io/github/followers/muhammad-fiaz?label=Follow&style=social)](https://github.com/muhammad-fiaz)
[![Discord](https://img.shields.io/badge/Discord-Join%20us-7289DA?logo=discord&style=flat-square)](https://discord.gg/ShaDFdZ7)
[![Discord](https://img.shields.io/badge/Discord-Join%20us-7289DA?logo=discord&style=flat-square)](https://discord.gg/mXMhy2EX)

</div>

Expand All @@ -36,6 +36,11 @@ This project is built with Next.js and React, showcasing [Muhammad Fiaz](https:/

**Support me with a little [sponsor ❤️](https://github.com/sponsors/muhammad-fiaz)**

Here the Sample Performance of the Portfolio measured by [Lighthouse](https://developers.google.com/web/tools/lighthouse) in Chrome DevTools.

![performance](https://private-user-images.githubusercontent.com/75434191/391230424-4d9d12db-24ef-4e1f-9060-c15902e12453.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzU1NzEzODcsIm5iZiI6MTczNTU3MTA4NywicGF0aCI6Ii83NTQzNDE5MS8zOTEyMzA0MjQtNGQ5ZDEyZGItMjRlZi00ZTFmLTkwNjAtYzE1OTAyZTEyNDUzLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDEyMzAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQxMjMwVDE1MDQ0N1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTY5ZTgzYTEyYTJlNjM5MDljMjEyZGI2ZWQxYjNkMzFlOGZmOGRhNTAwODQyNTM2MzlkMWEyMDk2OGQ1NzQ1NWYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.8LFhF0xpJE_NPbm_4VZURWgP8lKk0Oh_M8__GoUkK90)


## Table of Contents

- [Release Notes](#release-notes)
Expand Down
15 changes: 11 additions & 4 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ const nextConfig: NextConfig = {
protocol: 'https',
hostname: 'avatars.githubusercontent.com',
port: '',
pathname: '/**'
}
]
}
pathname: '/**',
},
{
protocol: 'https',
hostname: 'skillicons.dev',
port: '',
pathname: '/icons',
},
],
dangerouslyAllowSVG: true, // Allow SVG images
},
};

export default nextConfig;
71 changes: 50 additions & 21 deletions pages/api/fetch-projects.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
import { siteConfig } from '@/src/configs/config';

const GITHUB_USERNAME = siteConfig.social.github;
const GITHUB_TOKEN = process.env.GITHUB_TOKEN; // Retrieve the GitHub token from .env.local
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;

if (!GITHUB_TOKEN) {
throw new Error('GitHub token is not defined in .env.local');
}

// In-memory cache to store repository data
let cache: {
data: any;
timestamp: number;
} = { data: null, timestamp: 0 };

// Cache expiration time (in milliseconds)
const CACHE_EXPIRATION = 10 * 60 * 1000; // 10 minutes

export default async function handler(
req: { query: { search?: string } },
res: {
status: (arg0: number) => { (): any; new (): any; json: (arg0: any) => void };
}
) {
const { search } = req.query; // Get the search query from the URL (optional)
const { search } = req.query;

try {
// Check if cached data is still valid
const now = Date.now();
if (cache.data && now - cache.timestamp < CACHE_EXPIRATION) {
console.log('Serving data from cache');
return sendFilteredProjects(cache.data, search, res);
}

// Fetch data from GitHub API
const response = await fetch(
`https://api.github.com/users/${GITHUB_USERNAME}/repos?sort=updated&per_page=100`,
{
headers: {
Authorization: `token ${GITHUB_TOKEN}` // Include the token in the request header
}
Authorization: `token ${GITHUB_TOKEN}`,
},
}
);

Expand All @@ -39,8 +56,8 @@ export default async function handler(
{
headers: {
Authorization: `token ${GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json',
}
Accept: 'application/vnd.github.v3+json',
},
}
);

Expand All @@ -54,27 +71,39 @@ export default async function handler(
category: repo.language ? repo.language.toLowerCase() : 'unknown',
repo: repo.html_url,
link: repo.homepage || repo.html_url,
topics, // Add topics to the project data
topics,
};
})
);

// Filter projects based on the search query if provided
const filteredProjects = search
? projectsWithTopics.filter(
(project: { category: string; title: string; topics: string[] }) =>
project.category.toLowerCase().includes(search.toLowerCase()) ||
project.title.toLowerCase().includes(search.toLowerCase()) ||
project.topics.some((topic) =>
topic.toLowerCase().includes(search.toLowerCase())
)
)
: projectsWithTopics;

// Send the filtered projects as a response
res.status(200).json(filteredProjects);
// Cache the fetched data
cache = {
data: projectsWithTopics,
timestamp: Date.now(),
};

sendFilteredProjects(projectsWithTopics, search, res);
} catch (error) {
console.error('Error fetching GitHub repositories:', error);
res.status(500).json({ message: 'Error fetching repositories' });
}
}

function sendFilteredProjects(
projects: any[],
search: string | undefined,
res: any
) {
const filteredProjects = search
? projects.filter(
(project: { category: string; title: string; topics: string[] }) =>
project.category.toLowerCase().includes(search.toLowerCase()) ||
project.title.toLowerCase().includes(search.toLowerCase()) ||
project.topics.some((topic) =>
topic.toLowerCase().includes(search.toLowerCase())
)
)
: projects;

res.status(200).json(filteredProjects);
}
67 changes: 52 additions & 15 deletions pages/api/fetchRSS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,56 @@
import Parser from 'rss-parser';
import { siteConfig } from '@/src/configs/config';

export default async function handler(req: any, res: any) {
const parser = new Parser();
const feed = await parser.parseURL(`${siteConfig.social.blog}/rss.xml`);

// Assuming `feed.items` contains a `categories` field for tags
const blogs = feed.items.map((item: any) => ({
guid: item.guid,
title: item.title,
link: item.link,
contentSnippet: item.contentSnippet,
categories: item.categories || [], // Categories (tags)
source: item.source?.title || 'Hashnode' // Get the source blog title
}));

res.status(200).json({ items: blogs });
// Define the type for a blog post
interface BlogPost {
guid: string;
title: string;
link: string;
contentSnippet: string;
categories: string[]; // Categories (tags)
source: string; // Source blog title
}

// Cache setup
let cache: BlogPost[] | null = null;
let lastCacheTime: number = 0;
const CACHE_DURATION = 10 * 60 * 1000; // 10 minutes in milliseconds

export default async function handler(
req: { method: string },
res: { status: (statusCode: number) => any; json: (data: any) => void }
) {
const currentTime = Date.now();

// Check if data is available in the cache and still valid
if (cache && currentTime - lastCacheTime < CACHE_DURATION) {
console.log('Serving RSS feed from cache');
return res.status(200).json({ items: cache });
}

console.log('Fetching new RSS feed data');

try {
const parser = new Parser();
const feed = await parser.parseURL(`${siteConfig.social.blog}/rss.xml`);

// Assuming `feed.items` contains a `categories` field for tags
const blogs: BlogPost[] = feed.items.map((item: any) => ({
guid: item.guid || '',
title: item.title || '',
link: item.link || '',
contentSnippet: item.contentSnippet || '',
categories: item.categories || [], // Categories (tags)
source: item.source?.title || 'Hashnode', // Get the source blog title
}));

// Update the cache
cache = blogs;
lastCacheTime = currentTime;

res.status(200).json({ items: blogs });
} catch (error) {
console.error('Error fetching RSS feed:', error);
res.status(500).json({ message: 'Error fetching RSS feed' });
}
}
6 changes: 3 additions & 3 deletions public/sitemap-0.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
<url><loc>https://muhammadfiaz.com/robots.txt</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/manifest.webmanifest</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/robots.txt</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/blog</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/projects</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/home</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/about</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/home</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com/projects</loc><changefreq>daily</changefreq><priority>1</priority></url>
<url><loc>https://muhammadfiaz.com</loc><changefreq>daily</changefreq><priority>1</priority></url>
</urlset>
39 changes: 21 additions & 18 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
"use client";

import '@/src/styles/globals.css';
import clsx from 'clsx';
import local from 'next/font/local';
import Header from '@/src/components/ui/Header';
import Footer from '@/src/components/ui/Footer';
import FlareCursor from '@/src/components/ui/FlareCursor';
import ProgressBar from '@/src/components/utils/progress';
import BackToTopButton from '@/src/components/utils/BackToTopButton';
import Head from './head';
import { SpeedInsights } from '@vercel/speed-insights/next';
import { Analytics } from '@vercel/analytics/react';
import {NextUIProvider} from "@nextui-org/react";
import { NextUIProvider } from "@nextui-org/react";
import { SessionProvider } from 'next-auth/react';
import { ThemeProvider } from '../components/utils/themeContext';
import ProgressBar from '@/src/components/ui/progress';
import BackToTopButton from '@/src/components/ui/BackToTopButton';

const graphik = local({
src: [
Expand All @@ -35,29 +37,30 @@ const RootLayout = ({ children }: { children: React.ReactNode }) => {
<html
lang="en"
className={clsx(
'text-black bg-white dark:text-white dark:bg-[#111010] transition ease',
'text-foreground bg-background dark:text-foreground dark:bg-background transition ease-in-out',
graphik.variable
)}
>
<Head />

<body className="bg-[#080809] transition ease min-h-screen ">
<body className="transition ease-in-out min-h-screen">
<SessionProvider>
<NextUIProvider>

<ProgressBar />
<Header />
<ThemeProvider>
<NextUIProvider>
<ProgressBar />
<Header />

<main className="flex flex-col justify-center items-center mx-auto">
<FlareCursor />
{children}
<SpeedInsights />
<Analytics />
</main>
<BackToTopButton />
<main className="flex flex-col justify-center items-center mx-auto">
<FlareCursor />
{children}
<SpeedInsights />
<Analytics />
</main>

<Footer />
</NextUIProvider>
<BackToTopButton />
<Footer />
</NextUIProvider>
</ThemeProvider>
</SessionProvider>
</body>
</html>
Expand Down
14 changes: 8 additions & 6 deletions src/components/content/AboutMe.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
"use client";

import AnimationContainer from '../utils/AnimationContainer';
import { siteConfig } from '@/src/configs/config';

const AboutMe = () => {
return (
<AnimationContainer customClassName="w-full mb-16">
<h2 className="font-bold text-2xl tracking-tight mb-8 text-white text-center lg:text-start">
<h2 className="font-bold text-2xl tracking-tight mb-8 text-foreground dark:text-white text-center lg:text-start">
About Me
</h2>

<p className="text-base text-gray-400">
Hey there! 👋 I'm <strong>{siteConfig.author}</strong>, and I've been
<p className="text-base text-foreground dark:text-white">
Hey there! 👋 I'm <strong className="text-foreground dark:text-white">{siteConfig.author}</strong>, and I've been
passionate about coding since I was a child. I fell in love with
programming at a young age, spending countless hours learning,
experimenting, and creating small projects. Over the years, this passion
has grown into a career as a Full Stack developer, where I continue to
build innovative solutions that solve real-world problems.
</p>

<p className="text-base text-gray-400 mt-4">
<p className="text-base text-foreground dark:text-white mt-4">
As I’ve evolved in my career, I’ve expanded my expertise into new areas
like Machine Learning (ML) and Artificial Intelligence (AI), diving deep
into neural networks and other cutting-edge technologies. But no matter
Expand All @@ -26,14 +28,14 @@ const AboutMe = () => {
boundaries of what’s possible.
</p>

<p className="text-base text-gray-400 mt-4">
<p className="text-base text-foreground dark:text-white mt-4">
Today, I’m not just focused on building apps and websites; I’m also
exploring DevOps tools like Docker, Kubernetes, and AWS to optimize and
scale my projects. I believe in continuous learning and growth, and I’m
always looking for new challenges that help me expand my skills.
</p>

<p className="text-base text-gray-400 mt-4">
<p className="text-base text-foreground dark:text-white mt-4">
If you’re interested in collaborating on something exciting or need help
with a project, feel free to reach out. Let’s create something amazing
together!
Expand Down
Loading

0 comments on commit 6a59223

Please sign in to comment.