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) => ( + + ))} + } /> + );