diff --git a/app/(site)/components/AboutSection/AboutSection.tsx b/app/(site)/components/AboutSection/AboutSection.tsx index 3b11d144..3dbdda32 100644 --- a/app/(site)/components/AboutSection/AboutSection.tsx +++ b/app/(site)/components/AboutSection/AboutSection.tsx @@ -2,6 +2,8 @@ import Reader from "@/components/Reader/Reader"; import LanguageSection from "./LanguageSection"; import TechnologiesSection from "./TechnologiesSection"; import getMarkdownFromFileSystem from "@/actions/file-system/getMarkdownFromFileSystem"; +import { Button } from "@/components/shadcn/ui/button"; +import Link from "next/link"; /** * About section component. @@ -20,8 +22,9 @@ const AboutSection = () => { * About me written in markdown. * This markdown is converted to HTML and displayed on the page. */ - const blogContent: string | undefined = - getMarkdownFromFileSystem(`public/about-me.md`)?.content; + const blogContent: string | undefined = getMarkdownFromFileSystem( + `public/about/short.md` + )?.content; return (
@@ -45,7 +48,19 @@ const AboutSection = () => { Get to know me! - +
+ + + {`Read More About Me!`} + +
{/* Right section */} diff --git a/app/about/page.tsx b/app/about/page.tsx new file mode 100644 index 00000000..9b1a9a7b --- /dev/null +++ b/app/about/page.tsx @@ -0,0 +1,102 @@ +import type { Metadata } from "next"; +import developerName from "@/constants/developerName"; +import getMarkdownFromFileSystem from "@/actions/file-system/getMarkdownFromFileSystem"; +import { notFound } from "next/navigation"; +import HeadingTwo from "@/components/Text/HeadingTwo"; +import Reader from "@/components/Reader/Reader"; +import Image from "next/image"; +import DetailsTable from "@/components/UI/DetailsTable"; +import Socials from "@/components/Socials/Socials"; + +const aboutContent: string | undefined = + getMarkdownFromFileSystem(`public/about/long.md`)?.content; + +export const metadata: Metadata = { + title: `${developerName} - About Me`, + description: aboutContent, +}; + +/** + * About page displays information about the developer. + * @returns Home page + */ +export default function About() { + if (!aboutContent) { + notFound(); + } + + return ( +
+
+ +
+ + {/* Profile Image */} +
+
+ Profile image of the developer +
+
+ +
+ {/* Left section */} +
+ +
+ + {/* Right section */} +
+ {/* Profile Image */} + Profile image of the developer + + {/* Social Icons */} +
+ +
+ + {/* Details */} + +
+
+
+ ); +} diff --git a/app/education/[courseKey]/page.tsx b/app/education/[courseKey]/page.tsx index 084a80bd..67b712b0 100644 --- a/app/education/[courseKey]/page.tsx +++ b/app/education/[courseKey]/page.tsx @@ -1,4 +1,3 @@ -import generateUrl from "@/actions/generateUrl"; import filterMaterialByArchivedStatus from "@/actions/material/filter/filterMaterialByArchivedStatus"; import groupMaterialsByCategory from "@/actions/material/group/groupMaterialsByCategory"; import filterSkillsByType from "@/actions/skills/filter/filterSkillsByType"; @@ -11,21 +10,20 @@ import HeadingFour from "@/components/Text/HeadingFour"; import HeadingThree from "@/components/Text/HeadingThree"; import HeadingTwo from "@/components/Text/HeadingTwo"; import Grid from "@/components/UI/Grid"; -import PageDescription from "@/components/UI/PageDescription"; import { AspectRatio } from "@/components/shadcn/ui/aspect-ratio"; import developerName from "@/constants/developerName"; import { EDUCATION_PAGE } from "@/constants/pages"; import courseDatabaseMap from "@/database/Courses/CourseDatabaseMap"; +import CourseInterface from "@/database/Courses/CourseInterface"; +import ModuleDatabaseKeys from "@/database/Modules/ModuleDatabaseKeys"; import moduleDatabaseMap, { moduleDatabaseKeys, } from "@/database/Modules/ModuleDatabaseMap"; -import skillDatabaseMap from "@/database/Skills/SkillDatabaseMap"; +import ModuleInterface from "@/database/Modules/ModuleInterface"; import SkillDatabaseKeys from "@/database/Skills/SkillDatabaseKeys"; -import ModuleDatabaseKeys from "@/database/Modules/ModuleDatabaseKeys"; +import skillDatabaseMap from "@/database/Skills/SkillDatabaseMap"; import SkillTypesEnum from "@/enums/Skill/SkillTypesEnum"; import MaterialGroupInterface from "@/interfaces/material/MaterialGroupInterface"; -import CourseInterface from "@/database/Courses/CourseInterface"; -import ModuleInterface from "@/database/Modules/ModuleInterface"; import GroupedSkillsCategoriesInterface from "@/interfaces/skills/GroupedSkillsInterface"; import { Metadata, ResolvingMetadata } from "next"; import Image from "next/image"; diff --git a/app/more/page.tsx b/app/more/page.tsx new file mode 100644 index 00000000..b5f3bb68 --- /dev/null +++ b/app/more/page.tsx @@ -0,0 +1,53 @@ +import Grid from "@/components/UI/Grid"; +import PageNavigationItem from "@/components/UI/PageNavigationItem"; +import developerName from "@/constants/developerName"; +import NAV_ITEMS, { HOME_PAGE, MORE_PAGE } from "@/constants/pages"; +import NavigationItemInterface from "@/interfaces/NavigationItemInterface"; + +/** + * Generates the metadata for the page to navigate all pages. + * This includes the title and description of the page. + * This is used for SEO purposes. + * + * @param props The props for the page. + * @param parent The parent metadata that is being resolved. + * @returns The metadata for the page. + * @see https://nextjs.org/docs/app/building-your-application/optimizing/metadata + */ +export const metadata = { + title: `${developerName} - All Pages`, + description: MORE_PAGE.description, +}; + +type MorePageProps = { + params: { courseKey: string }; + searchParams: { [key: string]: string | string[] | undefined }; +}; + +/** + * Page displaying all the all the pages the user can navigate to. + * Some pages are not shown in the navbar and can only be accessed through this page. + * + * @returns Page to navigate all pages. + */ +const MorePage: React.FC = ({ params, searchParams }) => { + const ignoredPages: Array = [HOME_PAGE, MORE_PAGE]; + + return ( +
+
+
+ !ignoredPages.includes(item)).map( + (item) => ( + + ) + )} + /> +
+
+
+ ); +}; + +export default MorePage; diff --git a/components/Navbar/Navbar.tsx b/components/Navbar/Navbar.tsx index 2dbb5762..a6006f96 100644 --- a/components/Navbar/Navbar.tsx +++ b/components/Navbar/Navbar.tsx @@ -1,4 +1,5 @@ "use client"; + import { NAVBAR_HEIGHT } from "@/constants/NAVBAR"; import NAV_ITEMS from "@/constants/pages"; import { useNavbarStore } from "@/hooks/useNavbarStore"; @@ -8,6 +9,7 @@ import HomeButton from "./HomeButton"; import NavbarItem from "./NavbarItem"; import NavbarOverlay from "./NavbarOverlay"; import ThemeToggle from "./ThemeToggle"; +import NavbarSection from "./NavbarSection"; /** * Navbar component shown at the top of the page. @@ -62,6 +64,8 @@ export default function Navbar() {
+ + {/* Mobile Only */}
{/* Dark / Light Mode toggle for mobile */} @@ -82,30 +86,9 @@ export default function Navbar() {
-
-
- {/* Links */} - {NAV_ITEMS.map((item) => { - return ( -
- {item.label} -
- ); - })} - {/* Dark / Light Mode toggle for desktop */} -
- -
-
-
+ + {/* Desktop Only */} +
= ({ to, children }) => { +const NavbarItem: React.FC = ({ href, children }) => { const pathname: string = usePathname(); const { isOpen: isOverlayOpen, close: closeOverlay } = useNavbarStore(); @@ -32,7 +32,7 @@ const NavbarItem: React.FC = ({ to, children }) => { } } - let isActive: boolean = pathname === to; + let isActive: boolean = pathname === href; const navbarItemStyle = ` block lg:inline-block @@ -49,8 +49,10 @@ const NavbarItem: React.FC = ({ to, children }) => { `; return ( - handleClick()}> + handleClick()}> {children} + + {/* Hover Underline */} {/* Links */} - {items.map((item, index) => { - return ( -
- {item.label} -
- ); - })} + {items + .filter((item) => item.isMain) + .map((item, index) => { + return ( +
+ {item.label} +
+ ); + })}
diff --git a/components/Navbar/NavbarSection.tsx b/components/Navbar/NavbarSection.tsx new file mode 100644 index 00000000..b237866a --- /dev/null +++ b/components/Navbar/NavbarSection.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import NavbarItem from "./NavbarItem"; +import NavigationItemInterface from "@/interfaces/NavigationItemInterface"; +import ThemeToggle from "./ThemeToggle"; + +interface NavbarSectionProps { + items: Array; +} + +/** + * Section of the navbar that displays the links to the pages and the dark / light mode toggle. + * This is used for desktop devices and it is hidden on mobile devices. + * + * @param items Links and names of pages that can be accessed via the navbar + * @returns Component displaying the navbar section with the links to the pages + */ +const NavbarSection: React.FC = ({ items }) => { + return ( +
+
+ {/* Links */} + {items + .filter((item) => item.isMain) + .map((item) => { + return ( +
+ {item.label} +
+ ); + })} + + {/* Dark / Light Mode toggle for desktop */} +
+ +
+
+
+ ); +}; + +export default NavbarSection; diff --git a/components/Text/HeadingFour.tsx b/components/Text/HeadingFour.tsx index c5ddc0bc..9cec2c32 100644 --- a/components/Text/HeadingFour.tsx +++ b/components/Text/HeadingFour.tsx @@ -16,7 +16,7 @@ const HeadingFour: React.FC = ({ title }) => { className=" font-bold text-lg mb-2 - text-neutral-500 dark:text-neutral-400" + text-neutral-700 dark:text-neutral-200" > {title} diff --git a/components/UI/DetailsTable.tsx b/components/UI/DetailsTable.tsx index d8ed2f35..e00bdeb7 100644 --- a/components/UI/DetailsTable.tsx +++ b/components/UI/DetailsTable.tsx @@ -1,5 +1,6 @@ import React from "react"; import HeadingFour from "../Text/HeadingFour"; +import { twMerge } from "tailwind-merge"; interface TableDataPair { heading: string; @@ -8,18 +9,23 @@ interface TableDataPair { interface TableProps { details: TableDataPair[]; + className?: string; } /** * Component to render a grid of details. * Each detail consists of a heading and a corresponding value. * - * @param props Contains details, an array of TableDataPair. + * @param details The details to render as a list of titles and value pairs. + * @param className Custom class name to apply to the outer div. * @returns The rendered grid of details. */ -const DetailsTable: React.FC = ({ details }) => { +const DetailsTable: React.FC = ({ details, className }) => { + const baseStyle: string = `grid grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-4`; + const overlayStyle: string = twMerge(baseStyle, className); + return ( -
+
{details.map((detail, index) => (
diff --git a/components/UI/PageNavigationItem.tsx b/components/UI/PageNavigationItem.tsx new file mode 100644 index 00000000..1791e03f --- /dev/null +++ b/components/UI/PageNavigationItem.tsx @@ -0,0 +1,49 @@ +import NavigationItemInterface from "@/interfaces/NavigationItemInterface"; +import Link from "next/link"; +import React from "react"; + +interface PageNavigationItemProps { + item: NavigationItemInterface; +} + +/** + * Displays a navigation item for the page which allows the user to navigate to the page. + * This is used in the more page to display all the pages the user can navigate to. + * + * @param item The navigation item to display. + * @returns The navigation item for the page. + */ +const PageNavigationItem: React.FC = ({ item }) => { + return ( + <> + +
+

+ {item.label} +

+

+ {item.description} +

+
+ + + ); +}; + +export default PageNavigationItem; diff --git a/constants/pages.ts b/constants/pages.ts index 38faecb4..af9e4213 100644 --- a/constants/pages.ts +++ b/constants/pages.ts @@ -25,8 +25,8 @@ export const PROJECTS_PAGE: NavigationItemInterface = { description: ` Discover my portfolio of projects, both current and archived. Use filters to narrow down projects by category, programming language, and technologies. - Archived projects are hidden by default. `, + isMain: true, }; /** @@ -39,8 +39,8 @@ export const CERTIFICATES_PAGE: NavigationItemInterface = { description: ` Explore my collection of certificates and qualifications. Use filters to refine your search by issuer and category. - Archived certificates are initially hidden. `, + isMain: true, }; /** @@ -67,6 +67,7 @@ export const EDUCATION_PAGE: NavigationItemInterface = { description: ` Explore my education history and qualifications and view the modules I have studied. `, + isMain: true, }; /** @@ -81,7 +82,9 @@ export const EXPERIENCE_PAGE: NavigationItemInterface = { Dive into my professional journey. Discover the roles I've embraced, projects I've spearheaded, and the impact I've made. `, + isMain: true, }; + /** * Navigation item for the skills page. * This is where the user can view my skills and filter them according to their preferences. @@ -95,19 +98,50 @@ export const SKILL_PAGE: NavigationItemInterface = { `, }; +/** + * Navigation item for the about page. + * This is where the user can read a summary about me, my journey, and my aspirations. + */ +export const ABOUT_PAGE: NavigationItemInterface = { + label: "About", + path: "/about", + description: ` + Read a summary about me, my journey, and my aspirations. + `, +}; + +/** + * Navigation item for the more page. + * This is where the user can navigate to all the pages on the website. + */ +export const MORE_PAGE: NavigationItemInterface = { + label: "More", + path: "/more", + description: ` + Page where you can navigate to all the pages on the website. + This will also show other pages that are not displayed in the navbar. + `, + isMain: true, +}; + /** * List of navigation items that are displayed in the navbar. * If the constant is not added here, it will not be displayed in the navbar. + * If the `isMain` property is set to true, the item will be displayed in the navbar. * Users can navigate to these pages by clicking on the respective items. * The description may be displayed on every page and it is used for SEO purposes. * The order of the items is the order that is used when displaying the items on the website. */ const NAV_ITEMS: Array = [ + HOME_PAGE, PROJECTS_PAGE, EXPERIENCE_PAGE, EDUCATION_PAGE, CERTIFICATES_PAGE, + ABOUT_PAGE, BLOG_PAGE, + SKILL_PAGE, + MORE_PAGE, ]; export default NAV_ITEMS; diff --git a/interfaces/NavigationItemInterface.ts b/interfaces/NavigationItemInterface.ts index 4d1c6580..fc95cb83 100644 --- a/interfaces/NavigationItemInterface.ts +++ b/interfaces/NavigationItemInterface.ts @@ -7,9 +7,11 @@ * - `label`: the label of the navigation item * - `path`: the URL path of the navigation item the user will be redirected to * - `description`: the description of the page the user will be redirected to for SEO purposes + * - `isMain`: whether the page is a main page in the website */ export default interface NavigationItemInterface { label: string; path: string; description: string; + isMain?: boolean; } diff --git a/public/about-me.md b/public/about-me.md deleted file mode 100644 index 13c39627..00000000 --- a/public/about-me.md +++ /dev/null @@ -1,6 +0,0 @@ -Greetings! I'm Maruf, a **software engineer** from Royal Holloway University with a First Class Honours in Computer Science. My journey is driven intensely by **curiosity** and an unyielding passion for innovative technology. - -My experience spans the **software development lifecycle**. Yet, I see every day as a new opportunity to learn. With a penchant for **constantly adapting**, pushing boundaries, and challenging the norms, my explorations have led me into the depths of **Machine Learning** and **Mathematics**. Presently, I'm deepening my understanding of advanced ML techniques. - - -Outside the realm of code, my passions include football, badminton, science literature, and travel. Every day is an adventure, and I believe in **seizing every moment** with **unbridled enthusiasm**. \ No newline at end of file diff --git a/public/about/long.md b/public/about/long.md new file mode 100644 index 00000000..63f5bc00 --- /dev/null +++ b/public/about/long.md @@ -0,0 +1,7 @@ +I hold a First-Class Honours degree in Computer Science from Royal Holloway University of London. I have proven experience working with Python, JavaScript, and TypeScript, and have expertise in managing and designing both relational and non-relational databases. Additionally, I have a strong foundation in various Mathematical disciplines, including Algebra, Calculus, Statistics and more. Currently, I serve as a DevOps engineer at Commerzbank, where my responsibilities also encompass Software Engineering. + +I participated in several projects that have honed my skills across software and web development, Machine Learning, and software engineering processes. Notable projects include Circus Discussions, a social media platform built with TypeScript, Next.js, React, and Firebase, featuring CI/CD pipelines and Docker for efficient deployments. Another is a Machine Learning endeavour, the House Price Prediction project, where I used algorithms like Random Forest Regressor and Linear Regressors to predict housing prices in California, utilising tools such as Scikit Learn, Pandas and more. Additionally, I contributed to Noodle, a student learning platform, where I managed team tasks and timelines, enhancing my leadership and organizational skills. These experiences have been crucial in developing my ability to produce high-quality, well-documented, and tested code. + +In addition to my formal education, I've enriched my knowledge and skills through various online courses covering programming, software engineering, web development, machine learning, AI, DevOps, and mathematics. These courses have been vital for both my career and personal projects. I actively contributed to the GNOME Foundation, particularly in the development of the quick settings feature for GNOME 43, providing valuable feedback, mockups, and engaging in community discussions. Furthermore, I participated in the Google X RHUL Developers Club, collaborating on web development projects with fellow students. These experiences have deepened my understanding and practical skills in a collaborative, real-world environment. + +My diverse roles have honed my abilities in communication, task management, time management, problem-solving, and planning. Currently, I work at Commerzbank as a DevOps and software engineer, where my role as a team leader has been essential in developing my collaboration and leadership skills. Additionally, my experience as a Maths tutor has strengthened my communication skills, enabling me to effectively interact not only with students but also with their parents. These experiences collectively underscore my proficiency in both technical and soft skills, vital for my professional growth. \ No newline at end of file diff --git a/public/about/short.md b/public/about/short.md new file mode 100644 index 00000000..dfa495f8 --- /dev/null +++ b/public/about/short.md @@ -0,0 +1,5 @@ +I'm a proud alumnus of Royal Holloway University of London, where I earned a **First-Class Honours** degree in **Computer Science**. + +My professional journey is deeply rooted in a broad spectrum of technical fields, including **Software Engineering**, **Web Development**, **Machine Learning**, **DevOps**, and **Mathematics**. Over the years, I have completed numerous **projects** and obtained several **certifications** that demonstrate my expertise and commitment to these areas. + +Currently, I work as a **DevOps Engineer** at Commerzbank, where I apply my extensive skills to optimise and enhance operational workflows. Additionally, I am actively involved in **volunteering** within the field, contributing my time and expertise to various initiatives. \ No newline at end of file