Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 10 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
[![Watch tutorial here](https://img.youtube.com/vi/sUKptmUVIBM/0.jpg)](https://youtu.be/sUKptmUVIBM)

# [Watch video here](https://youtu.be/sUKptmUVIBM)

## What you will learn

- Latest Next.js 13 features
- Next.js App Router
- Next.js Server Actions
- Client & Server Components
- TypeScript (Beginner & Intermediate)
- Tailwind CSS
- Context API
- Advanced Animations with Framer Motion
- React.Email & Resend
- Custom React hooks
- Fresh, modern UI design
- Light & Dark mode
- Responsive website
# My portfolio!!

## Made using
- React & Next.js,
- TypeScript,
- Tailwind CSS,
- Framer Motion,
- React Email & Resend,
- Vercel hosting
## Important

If you want to be a professional developer, you have to know the fundamentals like JavaScript and CSS really well. I highly recommend you go through my [Professional JavaScript](https://bytegrad.com/courses/professional-javascript) and [Professional CSS](https://bytegrad.com/courses/professional-css) courses.

I'm close to releasing a complete React & Next.js course. Get on the email list to receive early-bird pricing: [link](https://email.bytegrad.com/).

## Setup

1. Add RESEND_API_KEY environment variable in .env.local
2. In the send-email.ts action file, change the "to" email to your own email
1. Add your own RESEND_API_KEY environment variable in .env.local
2. In the send-email.this shi file, change the "to" email to your own
70 changes: 34 additions & 36 deletions actions/sendEmail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,43 @@
import React from "react";
import { Resend } from "resend";
import { validateString, getErrorMessage } from "@/lib/utils";
import ContactFormEmail from "@/email/contact-form-email";
import ContactFormEmail from "@/email/contact-form-email"

const resend = new Resend(process.env.RESEND_API_KEY);

export const sendEmail = async (formData: FormData) => {
const senderEmail = formData.get("senderEmail");
const message = formData.get("message");
const senderEmail = formData.get('senderEmail');
const message = formData.get('message');

// simple server-side validation
if (!validateString(senderEmail, 500)) {
return {
error: "Invalid sender email",
};
}
if (!validateString(message, 5000)) {
return {
error: "Invalid message",
};
}
if(!validateString(senderEmail, 500)) {
return {
error: "Invalid email"
}
}
if(!validateString(message, 5000)) {
return {
error: "Invalid message"
}
}

let data;
try {
data = await resend.emails.send({
from: "Contact Form <[email protected]>",
to: "[email protected]",
subject: "Message from contact form",
reply_to: senderEmail,
react: React.createElement(ContactFormEmail, {
message: message,
senderEmail: senderEmail,
}),
});
} catch (error: unknown) {
return {
error: getErrorMessage(error),
};
}

return {
data,
};
};
let data;
try {
await resend.emails.send({
from: 'Contact Form <[email protected]>',
to: '[email protected]',
subject: 'Important',
reply_to: senderEmail as string,
react: React.createElement(ContactFormEmail, {
message: message as string,
senderEmail: senderEmail as string
})
});
} catch (error: unknown) {
return {
error: getErrorMessage(error),
};
}
return {
data,
};
};
Binary file modified app/favicon.ico
Binary file not shown.
57 changes: 28 additions & 29 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
import Header from "@/components/header";
import "./globals.css";
import { Inter } from "next/font/google";
import ActiveSectionContextProvider from "@/context/active-section-context";
import Footer from "@/components/footer";
import ThemeSwitch from "@/components/theme-switch";
import ThemeContextProvider from "@/context/theme-context";
import Footer from '@/components/footer';
import './globals.css'
import Header from "@/components/header"
import ActiveSectionContextProvider from '@/context/active-section-context';
import { Inter } from 'next/font/google'
import { Toaster } from "react-hot-toast";
import ThemeSwitch from '@/components/theme-switch';
import ThemeContextProvider from '@/context/theme-context';

const inter = Inter({ subsets: ["latin"] });
const inter = Inter({ subsets: ['latin'] })

export const metadata = {
title: "Ricardo | Personal Portfolio",
description: "Ricardo is a full-stack developer with 8 years of experience.",
title: 'Maheer | Software Developer Portfolio',
description: "I'm Maheer, a software developer with over 3 years of experience in full-stack development",
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
children: React.ReactNode
}) {
return (
<html lang="en" className="!scroll-smooth">
<body
className={`${inter.className} bg-gray-50 text-gray-950 relative pt-28 sm:pt-36 dark:bg-gray-900 dark:text-gray-50 dark:text-opacity-90`}
>
<div className="bg-[#fbe2e3] absolute top-[-6rem] -z-10 right-[11rem] h-[31.25rem] w-[31.25rem] rounded-full blur-[10rem] sm:w-[68.75rem] dark:bg-[#946263]"></div>
<div className="bg-[#dbd7fb] absolute top-[-1rem] -z-10 left-[-35rem] h-[31.25rem] w-[50rem] rounded-full blur-[10rem] sm:w-[68.75rem] md:left-[-33rem] lg:left-[-28rem] xl:left-[-15rem] 2xl:left-[-5rem] dark:bg-[#676394]"></div>

<ThemeContextProvider>
<ActiveSectionContextProvider>
<Header />
{children}
<Footer />

<Toaster position="top-right" />
<ThemeSwitch />
</ActiveSectionContextProvider>
</ThemeContextProvider>
<html lang="en" className='!scroll-smooth'>
<body className={`${inter.className} bg-gray-50 text-gray-950 relative pt-28 sm:pt-36
dark:bg-gray-900 dark:text-gray-50 dark:text-opacity-90`}>
<div className = "bg-[#fbe2e3] absolute top-[-6rem] -z-10 right-[11rem] h-[31.25rem] w-[31.25rem] rounded-full blur-[10rem] sm:w-[68.75rem] dark:bg-[#946263]"></div>
<div className = "bg-[#dbd7fb] absolute top-[-1rem] -z-10 left-[-35rem] h-[31.25rem] w-[50rem] rounded-full blur-[10rem] sm:w-[68.75rem] md:left-[-33rem] lg:left-[-28rem] xl:left-[-15rem] 2xl:left-[-5rem] dark:bg-[#676394]"></div>

<ThemeContextProvider>
<ActiveSectionContextProvider>
<Header />
{children}
<Footer />
<Toaster position="top-right" />
</ActiveSectionContextProvider>
<ThemeSwitch />
</ThemeContextProvider>

</body>
</html>
);
)
}
16 changes: 8 additions & 8 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import About from "@/components/about";
import Contact from "@/components/contact";
import Experience from "@/components/experience";
import Intro from "@/components/intro";
import Projects from "@/components/projects";
import SectionDivider from "@/components/section-divider";
import Skills from "@/components/skills";
import Intro from "@/components/intro"
import SectionDivider from "@/components/section-divider"
import About from "@/components/about"
import Projects from "@/components/projects"
import Skills from "@/components/skills"
import Experience from "@/components/experience"
import Contact from "@/components/contact"

export default function Home() {
return (
Expand All @@ -17,5 +17,5 @@ export default function Home() {
<Experience />
<Contact />
</main>
);
)
}
82 changes: 38 additions & 44 deletions components/about.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,43 @@
"use client";
"use client"

import React from "react";
import SectionHeading from "./section-heading";
import { motion } from "framer-motion";
import { useSectionInView } from "@/lib/hooks";
import React, { useEffect } from 'react'
import SectionHeading from './section-heading'
import { motion } from "framer-motion"
import { useSectionInView } from "@/lib/hooks"

export default function About() {
const { ref } = useSectionInView("About");
const { ref } = useSectionInView('About',);

return (
<motion.section
ref={ref}
className="mb-28 max-w-[45rem] text-center leading-8 sm:mb-40 scroll-mt-28"
initial={{ opacity: 0, y: 100 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.175 }}
id="about"
>
<SectionHeading>About me</SectionHeading>
<p className="mb-3">
After graduating with a degree in{" "}
<span className="font-medium">Accounting</span>, I decided to pursue my
passion for programming. I enrolled in a coding bootcamp and learned{" "}
<span className="font-medium">full-stack web development</span>.{" "}
<span className="italic">My favorite part of programming</span> is the
problem-solving aspect. I <span className="underline">love</span> the
feeling of finally figuring out a solution to a problem. My core stack
is{" "}
<span className="font-medium">
React, Next.js, Node.js, and MongoDB
</span>
. I am also familiar with TypeScript and Prisma. I am always looking to
learn new technologies. I am currently looking for a{" "}
<span className="font-medium">full-time position</span> as a software
developer.
</p>

<p>
<span className="italic">When I'm not coding</span>, I enjoy playing
video games, watching movies, and playing with my dog. I also enjoy{" "}
<span className="font-medium">learning new things</span>. I am currently
learning about{" "}
<span className="font-medium">history and philosophy</span>. I'm also
learning how to play the guitar.
</p>
</motion.section>
);
return(
<motion.section ref={ref} className='mb-28 max-w-[45rem] text-center
leading-8 sm:mb-40 scroll-mt-28'
initial={{ opacity: 0, y: 100 }}
animate={{ opacity: 1, y: 0 }} //optional animate?
transition={{ delay: 0.175 }}
id = "about"
>
<SectionHeading>About me</SectionHeading>
<p className="mb-3"> I'm a
<span className="font-medium"> Computer Science</span> student with a passion for building efficient systems.
Currently working as a Research Assistant in a <span className="font-medium">Flask/React/Java</span> video analytics project,
which involves <span className="font-medium"> modifying hash tables and data structures</span> to ensure seamless data flow between the client and server.
I collaborate on integrating these changes with the frontend, ensuring <span className="italic"> proper API responses and maintaining consistency</span>.
I particularly enjoy coding in
<span className="font-medium"> Java and Python
</span> as well as <span className="font-medium"> crafting responsive frontends</span>.
</p>
<p className="mb-3"> My technical sweet spot includes <span className="font-medium">full-stack development</span> and
<span className="font-medium"> performance optimization:
</span> whether it be reducing bugs and errors by rigorous testing or improving my portfolio using <span className="font-medium">Next.js</span>.
Additionally, I have experience in troubleshooting issues related to <span className="font-medium"> data handling</span>, optimizing server-side logic in a
<span className="font-medium"> Biomedical Research Project</span>.
</p>

</motion.section>
)
}
/**<p>
I have great <span className="italic">interpersonal and communication skills</span> having worked in
a multitude of diverse teams for classes, research, competitions and more. I am genuinely passionate about {" "}
<span className="font-medium">programming and teamwork</span>, so I hope we can connect and contribute to something great!
</p> */
Loading