From 64d611d9c4feba090c33be4fa01450a473475a84 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 22 Aug 2026 07:41:32 +0000
Subject: [PATCH] Add URL-based deep linking and a vertical timeline for Career
Co-authored-by: 20kaushik02 <59662438+20kaushik02@users.noreply.github.com>
---
package-lock.json | 58 +++++++++++++++++++
package.json | 3 +-
src/App.js | 5 +-
src/components/Career.js | 120 +++++++++++++++++++--------------------
src/components/Menu.js | 26 ++++++---
5 files changed, 142 insertions(+), 70 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index aba89f4..bb057ba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"@mui/material": "^7.3.7",
"react": "^19.2.3",
"react-dom": "^19.2.3",
+ "react-router-dom": "^7.18.2",
"swiper": "^12.0.3"
},
"devDependencies": {
@@ -14996,6 +14997,57 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz",
+ "integrity": "sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.2.tgz",
+ "integrity": "sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.18.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-router/node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -15950,6 +16002,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
diff --git a/package.json b/package.json
index ae11a8c..1739ab2 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"@mui/material": "^7.3.7",
"react": "^19.2.3",
"react-dom": "^19.2.3",
+ "react-router-dom": "^7.18.2",
"swiper": "^12.0.3"
},
"devDependencies": {
@@ -41,4 +42,4 @@
"last 1 safari version"
]
}
-}
\ No newline at end of file
+}
diff --git a/src/App.js b/src/App.js
index 6c92bfa..f2cfbdb 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,4 +1,5 @@
import { createContext, useEffect, useMemo, useState } from 'react';
+import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import Menu from './components/Menu';
@@ -57,7 +58,9 @@ function App() {
-
+
+
+
diff --git a/src/components/Career.js b/src/components/Career.js
index a458d59..be48b64 100644
--- a/src/components/Career.js
+++ b/src/components/Career.js
@@ -1,4 +1,4 @@
-import { Divider, List, ListItem, ListItemText, Typography } from '@mui/material'
+import { Box, List, ListItem, ListItemText, Typography, useTheme } from '@mui/material'
import React, { Fragment } from 'react'
export const experiencesData = [
@@ -62,70 +62,68 @@ export const experiencesData = [
},
];
+// Simple, dependency-free vertical timeline: a dot + connecting line down the
+// left edge, with each entry's content to the right.
+const TimelineEntry = ({ exp, isLast }) => {
+ const theme = useTheme();
+ return (
+
+
+
+ {!isLast && (
+
+ )}
+
+
+
+ {exp.designation}, {exp.location}, {exp.startDate} - {exp.endDate || 'Present'}
+
+
+
+ {exp.desc.map((line, index) =>
+
+
+
+ )}
+
+
+
+
+ );
+};
+
+const TimelineSection = ({ title, entries }) => (
+
+
+ {title}
+
+
+ {entries.map((exp, idx) => (
+
+ ))}
+
+
+);
+
const Career = () => {
return (
<>
-
- Professional
-
- {experiencesData.filter(exp => exp.type === 'prof').map((exp, idx) =>
-
-
- {exp.designation}, {exp.location}, {exp.startDate} - {exp.endDate}
-
-
-
- {exp.desc.map((line, index) =>
-
-
-
- )}
-
-
-
- )}
-
-
- Education
-
- {experiencesData.filter(exp => exp.type === 'edu').map((exp, idx) =>
-
-
- {exp.designation}, {exp.location}, {exp.startDate} - {exp.endDate}
-
-
-
- {exp.desc.map((line, index) =>
-
-
-
- )}
-
-
-
- )}
-
-
- Volunteering
-
- {experiencesData.filter(exp => exp.type === 'extra').map((exp, idx) =>
-
-
- {exp.designation}, {exp.location}, {exp.startDate} - {exp.endDate}
-
-
-
- {exp.desc.map((line, index) =>
-
-
-
- )}
-
-
-
- )}
+ exp.type === 'prof')} />
+ exp.type === 'edu')} />
+ exp.type === 'extra')} />
>
)
}
-export default Career;
\ No newline at end of file
+export default Career;
diff --git a/src/components/Menu.js b/src/components/Menu.js
index 8c18545..1862f8d 100644
--- a/src/components/Menu.js
+++ b/src/components/Menu.js
@@ -1,4 +1,5 @@
import * as React from 'react';
+import { Route, Routes, Navigate, useLocation, useNavigate } from 'react-router-dom';
import AppBar from '@mui/material/AppBar';
import Avatar from '@mui/material/Avatar';
@@ -38,19 +39,19 @@ const drawerWidth = 240;
const menuSections = [
{
- key: 'landing', display_name: 'About', appbar_text: 'Hello There!', display_icon: ,
+ key: 'landing', path: '/', display_name: 'About', appbar_text: 'Hello There!', display_icon: ,
extLink: false, component:
},
{
- key: 'exp', display_name: 'Work', appbar_text: 'Journey', display_icon: ,
+ key: 'exp', path: '/work', display_name: 'Work', appbar_text: 'Journey', display_icon: ,
extLink: false, component:
},
{
- key: 'proj', display_name: 'Stuff', appbar_text: 'Workbench', display_icon: ,
+ key: 'proj', path: '/stuff', display_name: 'Stuff', appbar_text: 'Workbench', display_icon: ,
extLink: false, component:
},
{
- key: 'ints', display_name: 'Interests', appbar_text: 'My Interests', display_icon: ,
+ key: 'ints', path: '/interests', display_name: 'Interests', appbar_text: 'My Interests', display_icon: ,
extLink: false, component:
},
{
@@ -63,11 +64,17 @@ const menuSections = [
},
];
+const internalSections = menuSections.filter(menuItem => menuItem.extLink === false);
+
function Menu(props) {
const [mobileOpen, setMobileOpen] = React.useState(false);
const [isClosing, setIsClosing] = React.useState(false);
- const [activeSection, setActiveSection] = React.useState(menuSections[0]);
const { mode, toggleMode } = React.useContext(ColorModeContext);
+ const location = useLocation();
+ const navigate = useNavigate();
+
+ const activeSection = internalSections.find((menuItem) => menuItem.path === location.pathname)
+ || internalSections[0];
React.useEffect(() => {
document.title = `Kaushik | ${activeSection.display_name}`;
@@ -91,7 +98,7 @@ function Menu(props) {
const handleDrawerSelect = (selectedSectionKey) => {
handleDrawerClose();
const menuSection = menuSections.filter((menuItem) => menuItem.key === selectedSectionKey)[0];
- setActiveSection(menuSection);
+ navigate(menuSection.path);
}
const drawer = (
@@ -203,7 +210,12 @@ function Menu(props) {
sx={{ flexGrow: 1, padding: 1, width: { sm: `calc(100% - ${drawerWidth}px)` } }}
>
- {activeSection.component}
+
+ {internalSections.map((menuItem) => (
+
+ ))}
+ } />
+
);