Add dark mode, theme, and UI polish across the site

Co-authored-by: 20kaushik02 <59662438+20kaushik02@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-08-22 07:33:36 +00:00
committed by GitHub
parent de42149c8c
commit 6717cbb30e
6 changed files with 125 additions and 23 deletions

View File

@@ -3,8 +3,17 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#00695f" />
<meta name="description" content="Kaushik's portfolio website" /> <meta name="description" content="Kaushik's portfolio website" />
<meta property="og:title" content="Kaushik's Website" />
<meta property="og:description" content="Kaushik's portfolio website" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://knravish.me" />
<meta property="og:image" content="%PUBLIC_URL%/android-chrome-512x512.png" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Kaushik's Website" />
<meta name="twitter:description" content="Kaushik's portfolio website" />
<meta name="twitter:image" content="%PUBLIC_URL%/android-chrome-512x512.png" />
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
@@ -29,7 +38,6 @@
color="#5bbad5" color="#5bbad5"
/> />
<meta name="msapplication-TileColor" content="#00a300" /> <meta name="msapplication-TileColor" content="#00a300" />
<meta name="theme-color" content="#ffffff" />
<title>Kaushik's Website</title> <title>Kaushik's Website</title>
</head> </head>
<body> <body>

View File

@@ -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 Menu from './components/Menu';
import { getAppTheme } from './theme';
export const WidthContext = createContext(); 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() { function App() {
const [width, setWidth] = useState(0); const [width, setWidth] = useState(0);
const [mode, setMode] = useState(getInitialMode);
// Get window dimensions on resize // Get window dimensions on resize
useEffect(() => { useEffect(() => {
window.addEventListener("resize", updateWindowDimensions); window.addEventListener("resize", updateWindowDimensions);
@@ -20,10 +38,29 @@ function App() {
useEffect(() => { useEffect(() => {
updateWindowDimensions(); 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 ( return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>
<CssBaseline />
<WidthContext.Provider value={width}> <WidthContext.Provider value={width}>
<Menu /> <Menu />
</WidthContext.Provider> </WidthContext.Provider>
</ThemeProvider>
</ColorModeContext.Provider>
); );
} }

View File

@@ -16,14 +16,14 @@ const socialsData = [
const Landing = () => { const Landing = () => {
return ( return (
<> <>
<Typography variant="h4" p={2} align="left">
Hi, I'm Kaushik 👋
</Typography>
<List> <List>
{/* summary */} {/* summary */}
<ListItem> <ListItem>
<ListItemText <ListItemText
primary={"Welcome to my (messy) homepage. I like data!\ 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."} />
My passions lie in data engineering/analytics, distributed technologies,\
networks and security, web development, machine learning...\
you get the picture." } />
</ListItem> </ListItem>
{/* current endeavor */} {/* current endeavor */}
<ListItem> <ListItem>

View File

@@ -3,7 +3,6 @@ import * as React from 'react';
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Avatar from '@mui/material/Avatar'; import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import CssBaseline from '@mui/material/CssBaseline';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import Drawer from '@mui/material/Drawer'; import Drawer from '@mui/material/Drawer';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
@@ -16,6 +15,7 @@ import MenuIcon from '@mui/icons-material/Menu';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
import Tooltip from '@mui/material/Tooltip';
import LandingIcon from '@mui/icons-material/Home'; import LandingIcon from '@mui/icons-material/Home';
import ProjectsIcon from '@mui/icons-material/AccountTree'; 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 InterestsIcon from '@mui/icons-material/Headphones';
import ArticleIcon from '@mui/icons-material/Article'; import ArticleIcon from '@mui/icons-material/Article';
import BlogIcon from '@mui/icons-material/RateReview'; 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 Landing from './Landing';
// import LoremIpsum from './LoremIpsum'; // import LoremIpsum from './LoremIpsum';
@@ -30,6 +32,7 @@ import Projects from './Projects';
import Career from './Career'; import Career from './Career';
import { handleLinkClick } from '../utils/linkClick'; import { handleLinkClick } from '../utils/linkClick';
import UnderConstruction from './UnderConstruction'; import UnderConstruction from './UnderConstruction';
import { ColorModeContext } from '../App';
const drawerWidth = 240; const drawerWidth = 240;
@@ -64,6 +67,11 @@ function Menu(props) {
const [mobileOpen, setMobileOpen] = React.useState(false); const [mobileOpen, setMobileOpen] = React.useState(false);
const [isClosing, setIsClosing] = React.useState(false); const [isClosing, setIsClosing] = React.useState(false);
const [activeSection, setActiveSection] = React.useState(menuSections[0]); const [activeSection, setActiveSection] = React.useState(menuSections[0]);
const { mode, toggleMode } = React.useContext(ColorModeContext);
React.useEffect(() => {
document.title = `Kaushik | ${activeSection.display_name}`;
}, [activeSection]);
const handleDrawerClose = () => { const handleDrawerClose = () => {
setIsClosing(true); setIsClosing(true);
@@ -130,7 +138,6 @@ function Menu(props) {
return ( return (
<Box sx={{ display: 'flex' }}> <Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar <AppBar
position="fixed" position="fixed"
sx={{ sx={{
@@ -148,9 +155,14 @@ function Menu(props) {
> >
<MenuIcon /> <MenuIcon />
</IconButton> </IconButton>
<Typography variant="h6" noWrap component="div"> <Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
{activeSection.appbar_text} {activeSection.appbar_text}
</Typography> </Typography>
<Tooltip title={mode === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}>
<IconButton color="inherit" aria-label="toggle color mode" onClick={toggleMode}>
{mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
</IconButton>
</Tooltip>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
<Box <Box

View File

@@ -1,7 +1,9 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { Box, Button, Card, CardActionArea, CardActions, CardContent, CardMedia, Chip, List, ListItem, ListItemText, Typography } from '@mui/material'; import { Box, Button, Card, CardActionArea, CardActions, CardContent, CardMedia, Chip, List, ListItem, ListItemText, Stack, Typography } from '@mui/material';
import { Swiper, SwiperSlide } from 'swiper/react'; import { Swiper, SwiperSlide } from 'swiper/react';
import "swiper/css"; import "swiper/css";
import "swiper/css/pagination";
import "swiper/css/navigation";
import { Pagination, Navigation, EffectFade } from "swiper/modules"; import { Pagination, Navigation, EffectFade } from "swiper/modules";
import { WidthContext } from '../App'; import { WidthContext } from '../App';
@@ -82,8 +84,8 @@ const Projects = () => {
const width = useContext(WidthContext); const width = useContext(WidthContext);
const ProjectCard = ({ project }) => { const ProjectCard = ({ project }) => {
return ( return (
<Card sx={{ maxWidth: 400 }}> <Card sx={{ maxWidth: 400, height: '100%', display: 'flex', flexDirection: 'column' }}>
<CardActionArea> <CardActionArea sx={{ flexGrow: 1, alignItems: 'stretch', display: 'flex', flexDirection: 'column' }}>
<CardMedia <CardMedia
component="img" component="img"
height="140" height="140"
@@ -91,8 +93,8 @@ const Projects = () => {
alt={project.name} alt={project.name}
onClick={() => handleLinkClick(process.env.PUBLIC_URL + "Projects/" + project.img)} onClick={() => handleLinkClick(process.env.PUBLIC_URL + "Projects/" + project.img)}
/> />
<CardContent align="left"> <CardContent align="left" sx={{ flexGrow: 1 }}>
<Typography gutterBottom component="div"> <Typography gutterBottom component="div" variant="h6">
{project.name} {project.name}
</Typography> </Typography>
<List> <List>
@@ -102,11 +104,11 @@ const Projects = () => {
</ListItem> </ListItem>
)} )}
</List> </List>
<Box> <Stack direction="row" flexWrap="wrap" gap={1}>
{project.tools.map((tool, index) => {project.tools.map((tool, index) =>
<Chip key={index} label={tool} /> <Chip key={index} label={tool} size="small" />
)} )}
</Box> </Stack>
</CardContent> </CardContent>
</CardActionArea> </CardActionArea>
<CardActions> <CardActions>
@@ -132,7 +134,7 @@ const Projects = () => {
pagination={{ pagination={{
dynamicBullets: true, dynamicBullets: true,
}} }}
navigation={false} navigation={width >= 480}
speed={400} speed={400}
spaceBetween={10} spaceBetween={10}
slidesPerView={width >= 480 ? 2.6 : 1.1} slidesPerView={width >= 480 ? 2.6 : 1.1}
@@ -142,7 +144,7 @@ const Projects = () => {
{projectsData.map((project) => {projectsData.map((project) =>
<SwiperSlide sx={{ <SwiperSlide sx={{
width: 'auto', width: 'auto',
flexShrink: 0, height: '90%' flexShrink: 0, height: 'auto'
}} key={project.key}> }} key={project.key}>
<ProjectCard project={project} /> <ProjectCard project={project} />
</SwiperSlide> </SwiperSlide>

43
src/theme.js Normal file
View File

@@ -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)',
},
},
},
},
},
});