diff --git a/components/LeftPanel/index.tsx b/components/LeftPanel/index.tsx
index 0174509..e324a42 100644
--- a/components/LeftPanel/index.tsx
+++ b/components/LeftPanel/index.tsx
@@ -4,67 +4,259 @@ import Bio from "./Bio";
import MiniButton from "@/components/common/MiniButton";
import { IconTypes, LeftPanelOptions } from "@/components/Types/enum";
import { LeftPanelProps } from "@/components/Types";
-import { useState } from "react";
+import { useState, useEffect, useRef } from "react";
+import { motion, AnimatePresence, PanInfo } from "framer-motion";
+import { FiMenu, FiX, FiChevronLeft } from "react-icons/fi";
const LeftPanel = ({ clickedCategory, handleInteraction }: LeftPanelProps) => {
const [clicked, setClicked] = useState(LeftPanelOptions.ABOUT);
+ const [isOpen, setIsOpen] = useState(false);
+ const [dragProgress, setDragProgress] = useState(0);
+ const constraintsRef = useRef(null);
- return (
-
-
-
-
+ const menuItems = [
+ { text: LeftPanelOptions.ABOUT, icon: IconTypes.SEARCH },
+ { text: LeftPanelOptions.EXPERIENCE, icon: IconTypes.ALBUM },
+ { text: LeftPanelOptions.ACHIEVEMENTS, icon: IconTypes.MEDAL },
+ { text: LeftPanelOptions.PROJECTS, icon: IconTypes.PROJECTS },
+ ];
-
-
-
-
-
-
+ const handleMenuClick = (item: LeftPanelOptions) => {
+ setClicked(item);
+ setIsOpen(false);
+ };
+
+ const closeMenu = () => setIsOpen(false);
+
+ useEffect(() => {
+ const handleEscape = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') closeMenu();
+ };
+
+ if (isOpen) {
+ document.addEventListener('keydown', handleEscape);
+ document.body.style.overflow = 'hidden';
+ }
+
+ return () => {
+ document.removeEventListener('keydown', handleEscape);
+ document.body.style.overflow = 'unset';
+ };
+ }, [isOpen]);
-
{
+ const progress = Math.max(0, Math.min(1, -info.offset.x / 250));
+ setDragProgress(progress);
+ };
+
+ const handleDragEnd = (event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {
+ if (info.offset.x < -100 || info.velocity.x < -500) {
+ closeMenu();
+ }
+ setDragProgress(0);
+ };
+
+ return (
+ <>
+ {/* Mobile Header with Hamburger */}
+
+ setIsOpen(true)}
+ className="flex items-center gap-3 px-3 py-2 rounded-xl bg-neutral-100 dark:bg-neutral-800 hover:bg-neutral-200 dark:hover:bg-neutral-700 transition-colors duration-200"
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ aria-label="Open Menu"
>
-
-
- Hidden element... SSSHHHHH...🤫
-
+
+ Menu
+
+
+
+ {clicked === LeftPanelOptions.ABOUT ? "Portfolio": clicked}
+
+
+
+
+
+
+
+
+ {menuItems.map((item, index) => (
+
+
+
+ ))}
+
+
+
+
+ Hidden element... SSSHHHHH...🤫
+
+
-
-
+
+
+ {/* Mobile Overlay Menu - Now from the LEFT */}
+
+ {isOpen && (
+ <>
+ {/* Backdrop */}
+
+
+ {/* Slide-out Panel */}
+
+
+ {/* Header */}
+
+
+ Profile
+
+
+
+
+
+
+ {/* Content */}
+
+
+
+
+
+
+
+
+ {menuItems.map((item, index) => (
+
+ handleMenuClick(item.text as LeftPanelOptions)}
+ clicked={clicked}
+ />
+
+ ))}
+
+
+
+
+
+
+
+ {/* Drag Hint */}
+
+
+
+
+
+
+
+ >
+ )}
+
+ >
);
};
diff --git a/config/site-config.ts b/config/site-config.ts
index 67dee7c..08b9062 100644
--- a/config/site-config.ts
+++ b/config/site-config.ts
@@ -529,13 +529,13 @@ export const siteConfig = {
description: "Portfolio website powered by Next.js, Tailwind CSS",
},
creator: "Balasubramanian T K",
- title: "Software Developer",
+ title: "Senior Software Engineer",
bio: "Web Developer & ELT Enthusiast, Competent with JavaScript and Python.",
location: "Kerala, India",
locationLink:
"https://maps.app.goo.gl/HTiGU32uhqhmVuBZ8",
email: "btk.codedev@gmail.com",
- footerText: `Built by @btkcodedev | ©${currentYear} btkcodedev. All Rights Reserved`,
+ footerText: `I am not Apple, so you could 'steal my work' (Hackintosh guys know this reference :P ), but karma always says to give credits`,
aboutItems: GridItems,
achievementItems: AchItems,
experienceItems: ExpItems,
diff --git a/package-lock.json b/package-lock.json
index 031a194..dc21d04 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -25,6 +25,7 @@
"postcss": "8.4.24",
"react": "^18",
"react-dom": "^18",
+ "react-icons": "^5.5.0",
"tailwind-merge": "^1.13.2",
"tailwindcss": "3.3.2",
"typescript": "5.1.3"
@@ -3788,6 +3789,15 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-icons": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+ "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
diff --git a/package.json b/package.json
index 215a8f6..91fa445 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
"name": "btkcodedev-portfolio",
- "version": "1.0.0",
+ "version": "2.0.0",
"private": true,
- "license": "UNLICENSED",
+ "license": "Proprietary",
"scripts": {
"dev": "next dev",
"build": "next build",
@@ -26,8 +26,9 @@
"postcss": "8.4.24",
"react": "^18",
"react-dom": "^18",
+ "react-icons": "^5.5.0",
"tailwind-merge": "^1.13.2",
"tailwindcss": "3.3.2",
"typescript": "5.1.3"
}
-}
\ No newline at end of file
+}
diff --git a/yarn.lock b/yarn.lock
index 3cabd1a..9359f6c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2241,6 +2241,11 @@ react-dom@*, react-dom@^18, react-dom@^18.0.0, react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
+react-icons@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz"
+ integrity sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==
+
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"