diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..efdb57e --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "portfolio", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "port": 3000, + "autoPort": false + } + ] +} diff --git a/package-lock.json b/package-lock.json index e4668a4..572af75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "portfolio", "version": "0.1.0", "dependencies": { + "framer-motion": "^12.40.0", "next": "16.2.6", "react": "19.2.4", "react-dom": "19.2.4" @@ -3762,6 +3763,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/framer-motion": { + "version": "12.40.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.40.0.tgz", + "integrity": "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.40.0", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5089,6 +5117,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/motion-dom": { + "version": "12.40.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.40.0.tgz", + "integrity": "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 9bd16a9..8683f2b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "eslint" }, "dependencies": { + "framer-motion": "^12.40.0", "next": "16.2.6", "react": "19.2.4", "react-dom": "19.2.4" diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41e..c79a9cd 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,8 +1,8 @@ @import "tailwindcss"; :root { - --background: #ffffff; - --foreground: #171717; + --background: #0a0a0a; + --foreground: #f5f5f5; } @theme inline { @@ -12,15 +12,25 @@ --font-mono: var(--font-geist-mono); } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } +html { + scroll-behavior: smooth; } body { background: var(--background); color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; +} + +::-webkit-scrollbar { + width: 5px; +} +::-webkit-scrollbar-track { + background: #0a0a0a; +} +::-webkit-scrollbar-thumb { + background: #f97316; + border-radius: 3px; +} +::-webkit-scrollbar-thumb:hover { + background: #fb923c; } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 976eb90..e99cf76 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -13,21 +13,17 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Khaalid.M.N Baccar — Software Engineer", + description: + "Software Engineer with hands-on experience in enterprise application development, SAP ERP solutions, and full-stack web development.", }; export default function RootLayout({ children, -}: Readonly<{ - children: React.ReactNode; -}>) { +}: Readonly<{ children: React.ReactNode }>) { return ( - - {children} + + {children} ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 3f36f7c..f27090a 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,65 +1,19 @@ -import Image from "next/image"; +import Navbar from "@/components/Navbar"; +import Hero from "@/components/Hero"; +import About from "@/components/About"; +import Skills from "@/components/Skills"; +import Projects from "@/components/Projects"; +import Contact from "@/components/Contact"; export default function Home() { return ( -
-
- Next.js logo -
-

- To get started, edit the page.tsx file. -

-

- Looking for a starting point or more instructions? Head over to{" "} - - Templates - {" "} - or the{" "} - - Learning - {" "} - center. -

-
-
- - Vercel logomark - Deploy Now - - - Documentation - -
-
-
+
+ + + + + + +
); } diff --git a/src/components/About.tsx b/src/components/About.tsx new file mode 100644 index 0000000..f5a60fb --- /dev/null +++ b/src/components/About.tsx @@ -0,0 +1,72 @@ +import SectionWrapper from "./SectionWrapper"; + +const stats = [ + { value: "1+", label: "Years Industry Experience" }, + { value: "1st", label: "Class Honours Degree" }, + { value: "15+", label: "Technologies" }, + { value: "2", label: "Languages Spoken" }, +]; + +const techHighlights = ["C#", "JavaScript", "Python", ".NET", "Node.js", "Angular"]; + +export default function About() { + return ( + +
+
+ 01. +

About Me

+
+
+ +
+
+

+ I'm a Software Engineer with hands-on experience in enterprise application + development and SAP ERP solutions. Currently working at{" "} + Accenture Technology in a + client-facing environment, delivering scalable and business-oriented software systems. +

+

+ I have a strong foundation in backend development, database systems, and API design, + with additional interest in game development and server infrastructure. I hold a{" "} + + BSc (Hons) in Software Engineering — First Class Honours + {" "} + from the University of Technology, Mauritius. +

+

+ I'm passionate about problem-solving, clean architecture, and continuous + technical growth. Whether it's building enterprise ERP solutions or personal + projects in AI and game development, I bring the same care and curiosity to + everything I work on. +

+ +
+ {techHighlights.map((tech) => ( + + {tech} + + ))} +
+
+ +
+ {stats.map(({ value, label }) => ( +
+
{value}
+
{label}
+
+ ))} +
+
+
+ + ); +} diff --git a/src/components/Contact.tsx b/src/components/Contact.tsx new file mode 100644 index 0000000..3966326 --- /dev/null +++ b/src/components/Contact.tsx @@ -0,0 +1,155 @@ +"use client"; + +import { useState } from "react"; +import SectionWrapper from "./SectionWrapper"; + +function GitHubIcon() { + return ( + + + + ); +} + +function LinkedInIcon() { + return ( + + + + ); +} + +function EmailIcon() { + return ( + + + + + ); +} + +const socials = [ + { label: "GitHub", href: "https://github.com", Icon: GitHubIcon }, + { label: "LinkedIn", href: "https://linkedin.com", Icon: LinkedInIcon }, + { label: "Email", href: "mailto:khaalidmnbaccar@gmail.com", Icon: EmailIcon }, +]; + +const CONTACT_EMAIL = "khaalidmnbaccar@gmail.com"; + +const inputClass = + "w-full bg-zinc-900/60 border border-zinc-800 rounded-lg px-4 py-3 text-white text-sm placeholder-zinc-600 focus:outline-none focus:border-orange-500/60 transition-colors"; + +export default function Contact() { + const [form, setForm] = useState({ name: "", email: "", message: "" }); + const [status, setStatus] = useState<"idle" | "opening">("idle"); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setStatus("opening"); + const subject = `Portfolio contact from ${form.name}`; + const body = `${form.message}\n\nReply to: ${form.email}`; + window.location.href = `mailto:${CONTACT_EMAIL}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`; + setTimeout(() => setStatus("idle"), 1500); + }; + + return ( + +
+
+ 04. +

Get In Touch

+
+
+ +

+ I'm open to new opportunities and collaborations. Whether you have a project in + mind or just want to connect — feel free to reach out. +

+ +
+
+
+ + setForm((f) => ({ ...f, name: e.target.value }))} + placeholder="Your name" + className={inputClass} + /> +
+
+ + setForm((f) => ({ ...f, email: e.target.value }))} + placeholder="your@email.com" + className={inputClass} + /> +
+
+
+ +