From 6717cbb30e0b712065bc7173afcd613103de7abe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Aug 2026 07:33:36 +0000 Subject: [PATCH] Add dark mode, theme, and UI polish across the site Co-authored-by: 20kaushik02 <59662438+20kaushik02@users.noreply.github.com> --- public/index.html | 12 ++++++++-- src/App.js | 45 ++++++++++++++++++++++++++++++++++---- src/components/Landing.js | 8 +++---- src/components/Menu.js | 18 ++++++++++++--- src/components/Projects.js | 22 ++++++++++--------- src/theme.js | 43 ++++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 src/theme.js diff --git a/public/index.html b/public/index.html index aa8b7d7..9f7b02f 100644 --- a/public/index.html +++ b/public/index.html @@ -3,8 +3,17 @@ - + + + + + + + + + + - Kaushik's Website diff --git a/src/App.js b/src/App.js index 97ab7b6..6c92bfa 100644 --- a/src/App.js +++ b/src/App.js @@ -1,10 +1,28 @@ -import { createContext, useEffect, useState } from 'react'; +import { createContext, useEffect, useMemo, useState } from 'react'; +import { ThemeProvider } from '@mui/material/styles'; +import CssBaseline from '@mui/material/CssBaseline'; import Menu from './components/Menu'; +import { getAppTheme } from './theme'; export const WidthContext = createContext(); +export const ColorModeContext = createContext({ mode: 'light', toggleMode: () => { } }); + +const THEME_STORAGE_KEY = 'colorMode'; + +function getInitialMode() { + const stored = window.localStorage.getItem(THEME_STORAGE_KEY); + if (stored === 'light' || stored === 'dark') { + return stored; + } + return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light'; +} function App() { const [width, setWidth] = useState(0); + const [mode, setMode] = useState(getInitialMode); + // Get window dimensions on resize useEffect(() => { window.addEventListener("resize", updateWindowDimensions); @@ -20,10 +38,29 @@ function App() { useEffect(() => { updateWindowDimensions(); }, []); + + const colorMode = useMemo(() => ({ + mode, + toggleMode: () => { + setMode((prevMode) => { + const nextMode = prevMode === 'light' ? 'dark' : 'light'; + window.localStorage.setItem(THEME_STORAGE_KEY, nextMode); + return nextMode; + }); + }, + }), [mode]); + + const theme = useMemo(() => getAppTheme(mode), [mode]); + return ( - - - + + + + + + + + ); } diff --git a/src/components/Landing.js b/src/components/Landing.js index 90d4a6f..b61b67e 100644 --- a/src/components/Landing.js +++ b/src/components/Landing.js @@ -16,14 +16,14 @@ const socialsData = [ const Landing = () => { return ( <> + + Hi, I'm Kaushik 👋 + {/* summary */} + primary={"Welcome to my (messy) homepage. I like data! My passions lie in data engineering/analytics, distributed technologies, networks and security, web development, machine learning... you get the picture."} /> {/* current endeavor */} diff --git a/src/components/Menu.js b/src/components/Menu.js index 1184189..8c18545 100644 --- a/src/components/Menu.js +++ b/src/components/Menu.js @@ -3,7 +3,6 @@ import * as React from 'react'; import AppBar from '@mui/material/AppBar'; import Avatar from '@mui/material/Avatar'; import Box from '@mui/material/Box'; -import CssBaseline from '@mui/material/CssBaseline'; import Divider from '@mui/material/Divider'; import Drawer from '@mui/material/Drawer'; import IconButton from '@mui/material/IconButton'; @@ -16,6 +15,7 @@ import MenuIcon from '@mui/icons-material/Menu'; import Toolbar from '@mui/material/Toolbar'; import Typography from '@mui/material/Typography'; import Link from '@mui/material/Link'; +import Tooltip from '@mui/material/Tooltip'; import LandingIcon from '@mui/icons-material/Home'; import ProjectsIcon from '@mui/icons-material/AccountTree'; @@ -23,6 +23,8 @@ import CareerIcon from '@mui/icons-material/Work'; import InterestsIcon from '@mui/icons-material/Headphones'; import ArticleIcon from '@mui/icons-material/Article'; import BlogIcon from '@mui/icons-material/RateReview'; +import LightModeIcon from '@mui/icons-material/LightMode'; +import DarkModeIcon from '@mui/icons-material/DarkMode'; import Landing from './Landing'; // import LoremIpsum from './LoremIpsum'; @@ -30,6 +32,7 @@ import Projects from './Projects'; import Career from './Career'; import { handleLinkClick } from '../utils/linkClick'; import UnderConstruction from './UnderConstruction'; +import { ColorModeContext } from '../App'; const drawerWidth = 240; @@ -64,6 +67,11 @@ 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); + + React.useEffect(() => { + document.title = `Kaushik | ${activeSection.display_name}`; + }, [activeSection]); const handleDrawerClose = () => { setIsClosing(true); @@ -130,7 +138,6 @@ function Menu(props) { return ( - - + {activeSection.appbar_text} + + + {mode === 'dark' ? : } + + { const width = useContext(WidthContext); const ProjectCard = ({ project }) => { return ( - - + + { alt={project.name} onClick={() => handleLinkClick(process.env.PUBLIC_URL + "Projects/" + project.img)} /> - - + + {project.name} @@ -102,11 +104,11 @@ const Projects = () => { )} - + {project.tools.map((tool, index) => - + )} - + @@ -132,7 +134,7 @@ const Projects = () => { pagination={{ dynamicBullets: true, }} - navigation={false} + navigation={width >= 480} speed={400} spaceBetween={10} slidesPerView={width >= 480 ? 2.6 : 1.1} @@ -142,7 +144,7 @@ const Projects = () => { {projectsData.map((project) => diff --git a/src/theme.js b/src/theme.js new file mode 100644 index 0000000..55cbc92 --- /dev/null +++ b/src/theme.js @@ -0,0 +1,43 @@ +import { createTheme } from '@mui/material/styles'; + +// Central place to tweak the site's look and feel. +export const getAppTheme = (mode) => createTheme({ + palette: { + mode, + primary: { + main: mode === 'dark' ? '#7ad0c9' : '#00695f', + }, + secondary: { + main: '#ef6c00', + }, + background: mode === 'dark' + ? { default: '#121212', paper: '#1c1c1c' } + : { default: '#f7f7f5', paper: '#ffffff' }, + }, + shape: { + borderRadius: 10, + }, + typography: { + fontFamily: [ + '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', '"Fira Sans"', '"Droid Sans"', '"Helvetica Neue"', + 'sans-serif', + ].join(','), + h5: { + fontWeight: 600, + }, + }, + components: { + MuiCard: { + styleOverrides: { + root: { + transition: 'transform 200ms ease, box-shadow 200ms ease', + '&:hover': { + transform: 'translateY(-4px)', + boxShadow: '0 8px 20px rgba(0,0,0,0.15)', + }, + }, + }, + }, + }, +});