Skip to content

Commit e75b45f

Browse files
committed
Update: resume, fix: heatmap, skillset, theme detection-based display, StakeLiGames pic UX
Fix: Skillset section UX, StakeLiGames project image Added system detection-based theme display Update heatmap color schema to GitHub default Interactive Override, Session Cleanup on Close, No Sticky Light/Dark State Chore: Added updated 2-pager resume
1 parent 85dd342 commit e75b45f

8 files changed

Lines changed: 102 additions & 47 deletions

File tree

public/SoumilM_KJSCE_Resume.pdf

36.6 KB
Binary file not shown.

src/components/Certf.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const Certf = () => {
5959
initial="hidden"
6060
whileInView="show"
6161
viewport={{ once: true, amount: 0.01 }}
62-
className="mx-auto w-fit px-6 py-4 mt-10 bg-black/80 rounded-xl backdrop-blur-md"
62+
className="mx-auto w-fit px-6 py-4 mt-6 bg-black/80 rounded-xl backdrop-blur-md"
6363
>
6464
<p className={`${styles.sectionSubText} text-center text-[#37b54a]`}>
6565
My Certifications

src/components/Heatmap.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ const Heatmap = () => {
1919
const { isLightMode } = useTheme();
2020

2121
const theme = {
22-
light: ["#e5e7eb","#c7f0d3","#80d49c","#45b96b","#188a42",],
23-
dark: ["#18181b","#123d22","#25924a","#2ea043","#3ddc84",],
22+
// GitHub's exact official contribution graph colors
23+
light: ["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"],
24+
dark: ["#161b22", "#0e4429", "#006d32", "#26a641", "#39d353"],
2425
};
2526

2627
const scrollToLatest = useCallback(() => {

src/components/Tech.jsx

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const skillGroups = [
1313
},
1414
{
1515
title: "Web & Full Stack",
16-
skills: ["HTML 5", "CSS 3", "React JS", "Next JS", "Node JS", "Flask"],
16+
skills: ["HTML 5", "CSS 3", "Tailwind CSS", "React JS", "Next JS", "Node JS", "Flask"],
1717
},
1818
{
1919
title: "AI, ML & Data",
@@ -29,7 +29,7 @@ const skillGroups = [
2929
},
3030
];
3131

32-
const SkillGroupCard = ({ title, skills, index }) => {
32+
const SkillGroup = ({ title, skills, index, isLast }) => {
3333
const { isLightMode } = useTheme();
3434
const groupSkills = skills
3535
.map((skillName) => technologies.find((tech) => tech.name === skillName))
@@ -41,31 +41,32 @@ const SkillGroupCard = ({ title, skills, index }) => {
4141
initial="hidden"
4242
whileInView="show"
4343
viewport={{ once: true, amount: 0.01 }}
44-
className="relative bg-black p-[2px] rounded-lg transition-transform border border-white/30 hover:border-[#37b54a]"
45-
whileHover={{ scaleY: 1.05 }}
44+
className="w-full"
4645
>
47-
<div className="bg-black p-5 rounded-lg h-full">
48-
<h3 className="text-[#37b54a] font-bold text-[22px] text-center transition-all duration-300">
49-
{title}
50-
</h3>
46+
{/* Domain Subheading with mode-compatible underline color */}
47+
<h3 className={`text-[#37b54a] font-bold text-[22px] text-left border-b pb-2 mb-6 ${isLightMode ? "border-[#2a322b]/20" : "border-white/30"}`}>
48+
{title}
49+
</h3>
5150

52-
<div className="mt-5 grid grid-cols-2 gap-4">
53-
{groupSkills.map((skill) => (
54-
<div
55-
key={`${title}-${skill.name}`}
56-
className="flex min-h-[94px] flex-col items-center justify-center rounded-lg border border-white/20 bg-black/80 px-3 py-4 text-center transition-colors duration-200 hover:border-[#37b54a]/80"
57-
>
51+
{/* Wrapping flex row of skill icons with responsive gap and spacing */}
52+
<div className={`flex flex-wrap gap-x-4 sm:gap-x-8 gap-y-6 justify-start ${isLast ? "mb-2" : "mb-8"}`}>
53+
{groupSkills.map((skill) => (
54+
<div
55+
key={`${title}-${skill.name}`}
56+
className="flex flex-col items-center justify-center text-center w-20 sm:w-24 group cursor-pointer"
57+
>
58+
<div className="w-16 h-16 flex items-center justify-center transition-transform duration-300 group-hover:scale-110">
5859
<img
5960
src={isLightMode && skill.iconLight ? skill.iconLight : skill.icon}
6061
alt={skill.name}
61-
className="h-10 w-10 object-contain"
62+
className="h-12 w-12 object-contain"
6263
/>
63-
<p className="mt-3 text-sm font-bold leading-tight text-white">
64-
{skill.name}
65-
</p>
6664
</div>
67-
))}
68-
</div>
65+
<p className="mt-2 text-sm font-semibold leading-tight text-white/80 skill-name transition-colors duration-300">
66+
{skill.name}
67+
</p>
68+
</div>
69+
))}
6970
</div>
7071
</motion.div>
7172
);
@@ -74,27 +75,26 @@ const SkillGroupCard = ({ title, skills, index }) => {
7475
const Tech = () => {
7576
return (
7677
<div>
77-
{/* Scroll animated section title with clear readable background */}
78+
{/* Section Title Heading with reduced top margin */}
7879
<motion.div
79-
variants={simpleFadeIn(0.05, 0.1)}
80-
initial="hidden"
81-
whileInView="show"
82-
viewport={{ once: true, amount: 0.01 }}
83-
className="mx-auto w-fit px-6 py-4 mt-10 bg-black/80 rounded-xl backdrop-blur-md"
84-
>
85-
<p className={`${styles.sectionSubText} text-center text-white`}>
86-
Technologies worked with
87-
</p>
88-
<h2 className={`${styles.sectionHeadText} text-center text-white`}>
89-
Skillset
90-
</h2>
91-
</motion.div>
92-
80+
variants={simpleFadeIn(0.05, 0.1)}
81+
initial="hidden"
82+
whileInView="show"
83+
viewport={{ once: true, amount: 0.01 }}
84+
className="mx-auto w-fit px-6 py-4 mt-6 bg-black bg-opacity-80 rounded-xl backdrop-blur-md"
85+
>
86+
<p className={`${styles.sectionSubText} text-center text-white`}>
87+
Technologies worked with
88+
</p>
89+
<h2 className={`${styles.sectionHeadText} text-center text-white`}>
90+
Skillset
91+
</h2>
92+
</motion.div>
9393

94-
{/* Grouped skill cards */}
95-
<div className="mt-20 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
94+
{/* Grouped Skills stacked vertically with reduced gap and margins */}
95+
<div className="mt-8 bg-black bg-opacity-80 rounded-lg p-8 backdrop-blur-sm max-w-5xl mx-auto flex flex-col gap-2">
9696
{skillGroups.slice(0, 5).map((group, index) => (
97-
<SkillGroupCard key={group.title} index={index} {...group} />
97+
<SkillGroup key={group.title} index={index} isLast={index === 4} {...group} />
9898
))}
9999
</div>
100100
</div>

src/components/Works.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { SectionWrapper } from "../hoc";
66
import { projects } from "../constants";
77
import { textVariant, simpleFadeIn } from "../utils/motion"; // Use simpleFadeIn!
88

9-
const ProjectCard = ({ index, name, description, tags, image, source_code_link }) => {
9+
const ProjectCard = ({ index, name, description, tags, image, source_code_link, imageClass }) => {
1010
return (
1111
<motion.div
1212
variants={simpleFadeIn(index * 0.05, 0.1)}
@@ -18,7 +18,7 @@ const ProjectCard = ({ index, name, description, tags, image, source_code_link }
1818
>
1919
<div className="bg-black p-5 rounded-lg w-full">
2020
<div className="relative w-full h-[230px] rounded-lg overflow-hidden">
21-
<img src={image} alt="project_image" className="w-full h-full object-cover rounded-lg" />
21+
<img src={image} alt="project_image" className={`w-full h-full ${imageClass || "object-cover"} rounded-lg`} />
2222
<div className="absolute inset-0 flex justify-end m-3 card-img_hover">
2323
<div
2424
onClick={() => window.open(source_code_link, "_blank")}

src/constants/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ const achievements = [
252252
{
253253
name: "Top 4% on Codolio, 1st rank in college",
254254
description:
255-
"Stats: 480+ DSA problems solved, 8 awards, 2600+ dev contributions & C-Score of 775+ among 35,700+ global users.",
255+
"Stats: 480+ DSA problems solved, 8 awards, 2700+ dev contributions & C-Score of 780+ among ~36,000 global users.",
256256
link: "https://codolio.com/profile/uQSHdtbA",
257257
},
258258
{
@@ -287,7 +287,7 @@ const projects = [
287287
{
288288
name: "SimulateRecruitAI",
289289
description:
290-
"Tech stack: Next, NeonDB, Docker, Clerk, Stripe, Tailwind, JSON, Gemini AI, API routes & Radix UI; achieved 80+ sign-ups.",
290+
"Tech stack: Next, NeonDB, Docker, Clerk, Stripe, Tailwind, JSON, Gemini AI, API routes & Radix UI; achieved ~90 sign-ups.",
291291
tags: [
292292
{
293293
name: "next",
@@ -345,6 +345,7 @@ const projects = [
345345
},
346346
],
347347
image: stakeligames,
348+
imageClass: "object-contain bg-white",
348349
source_code_link: "https://github.com/Soumilgit/StakeLiGames",
349350
},
350351
{

src/context/ThemeContext.jsx

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@ const ThemeContext = createContext(null);
55
export const ThemeProvider = ({ children }) => {
66
const [theme, setTheme] = useState(() => {
77
if (typeof window === "undefined") return "dark";
8-
return window.localStorage.getItem("portfolio-theme") || "dark";
8+
9+
// Only use cached theme if the user explicitly clicked the toggle button previously in this session
10+
const hasOverride = window.sessionStorage.getItem("portfolio-theme-override") === "true";
11+
if (hasOverride) {
12+
const savedTheme = window.localStorage.getItem("portfolio-theme");
13+
if (savedTheme) return savedTheme;
14+
}
15+
16+
// Otherwise, dynamically default to system preference
17+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
18+
return prefersDark ? "dark" : "light";
919
});
1020

1121
useEffect(() => {
@@ -15,11 +25,41 @@ export const ThemeProvider = ({ children }) => {
1525
window.localStorage.setItem("portfolio-theme", theme);
1626
}, [theme]);
1727

28+
useEffect(() => {
29+
if (typeof window === "undefined") return;
30+
31+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
32+
const handleSystemThemeChange = (e) => {
33+
const newTheme = e.matches ? "dark" : "light";
34+
setTheme(newTheme);
35+
};
36+
37+
if (mediaQuery.addEventListener) {
38+
mediaQuery.addEventListener("change", handleSystemThemeChange);
39+
} else {
40+
mediaQuery.addListener(handleSystemThemeChange);
41+
}
42+
43+
return () => {
44+
if (mediaQuery.removeEventListener) {
45+
mediaQuery.removeEventListener("change", handleSystemThemeChange);
46+
} else {
47+
mediaQuery.removeListener(handleSystemThemeChange);
48+
}
49+
};
50+
}, []);
51+
1852
const value = useMemo(
1953
() => ({
2054
theme,
2155
isLightMode: theme === "light",
22-
toggleTheme: () => setTheme((current) => (current === "light" ? "dark" : "light")),
56+
toggleTheme: () => {
57+
setTheme((current) => {
58+
const next = current === "light" ? "dark" : "light";
59+
window.sessionStorage.setItem("portfolio-theme-override", "true");
60+
return next;
61+
});
62+
},
2363
}),
2464
[theme]
2565
);

src/index.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,16 @@ html.light-mode .mobile-menu ul li:hover,
358358
html.light-mode .mobile-menu ul li:hover a {
359359
color: #37b54a !important;
360360
}
361+
362+
/* Slightly reduce vertical spacing between Tech (Skillset) and Certifications sections */
363+
section:has(#technologies) {
364+
padding-bottom: 40px !important;
365+
}
366+
section:has(#certf) {
367+
padding-top: 40px !important;
368+
}
369+
370+
/* Transiton skill label color to neon green on card/icon hover in both themes */
371+
.group:hover .skill-name {
372+
color: #37b54a !important;
373+
}

0 commit comments

Comments
 (0)