Skip to content

Commit 2bffd67

Browse files
committed
design: premium hero and portfolio polish
1 parent da4971b commit 2bffd67

4 files changed

Lines changed: 278 additions & 79 deletions

File tree

src/components/HeroSection.jsx

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,51 @@ export default function HeroSection() {
7373
};
7474
}, [problems, projects]);
7575

76+
const prefersReducedMotion =
77+
typeof window !== "undefined" &&
78+
typeof window.matchMedia === "function" &&
79+
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
80+
81+
const [metricDisplay, setMetricDisplay] = useState({
82+
repositories: prefersReducedMotion ? summary.repositories : 0,
83+
problems: prefersReducedMotion ? summary.problems : 0,
84+
verified: prefersReducedMotion ? summary.verified : 0,
85+
});
86+
87+
useEffect(() => {
88+
if (prefersReducedMotion) {
89+
setMetricDisplay({
90+
repositories: summary.repositories,
91+
problems: summary.problems,
92+
verified: summary.verified,
93+
});
94+
return undefined;
95+
}
96+
97+
let frameId = 0;
98+
const duration = 950;
99+
const start = performance.now();
100+
101+
const step = (now) => {
102+
const progress = Math.min(1, (now - start) / duration);
103+
const eased = 1 - Math.pow(1 - progress, 3);
104+
105+
setMetricDisplay({
106+
repositories: Math.round(summary.repositories * eased),
107+
problems: Math.round(summary.problems * eased),
108+
verified: Math.round(summary.verified * eased),
109+
});
110+
111+
if (progress < 1) {
112+
frameId = window.requestAnimationFrame(step);
113+
}
114+
};
115+
116+
frameId = window.requestAnimationFrame(step);
117+
118+
return () => window.cancelAnimationFrame(frameId);
119+
}, [prefersReducedMotion, summary.problems, summary.repositories, summary.verified]);
120+
76121
return (
77122
<main className="home-shell">
78123
<section className="hero" id="home">
@@ -86,24 +131,41 @@ export default function HeroSection() {
86131
<h4 className="hero-subtitle">{profile.name}</h4>
87132
<h1 className="hero-title">I build web apps that turn learning, coding, and workflows into usable products.</h1>
88133
<p className="hero-description">
89-
I&apos;m a full-stack focused developer building SunilCraft, coding-journal, and
90-
product-style tools with React, Node.js, GitHub workflows, and real project systems.
134+
MCA student at Bangalore University building developer tools, portfolio systems, coding workflows, and product-focused web applications with React and Node.js.
91135
</p>
92-
<div className="hero-actions">
93-
<Link to="/projects" className="hero-button">Explore Work</Link>
94-
<Link to="/dashboard" className="hero-button secondary">Open Dashboard</Link>
95-
<a href={profile.github} className="hero-button secondary" target="_blank" rel="noreferrer">GitHub</a>
136+
137+
<div className="hero-trust">
138+
<Badge tone="accent">GitHub synced</Badge>
139+
<Badge tone="success">Verified solutions</Badge>
140+
<Badge>Live coding journal</Badge>
96141
</div>
97142

98143
<div className="hero-stats" aria-label="Portfolio stats">
99-
<span><strong>{summary.repositories || "--"}</strong> Live Repos</span>
100-
<span><strong>{summary.problems || "--"}</strong> Problems</span>
101-
<span><strong>{summary.verified || "--"}</strong> Verified</span>
144+
<article className="hero-stat-card">
145+
<strong>{metricDisplay.repositories || 0}</strong>
146+
<span>Repositories</span>
147+
</article>
148+
<article className="hero-stat-card">
149+
<strong>{metricDisplay.problems || 0}</strong>
150+
<span>Problems Solved</span>
151+
</article>
152+
<article className="hero-stat-card">
153+
<strong>{metricDisplay.verified || 0}</strong>
154+
<span>Verified Solutions</span>
155+
</article>
102156
</div>
103157
</motion.div>
104158

105159
<div className="hero-image">
106-
<img src={HeroPic} alt="Sunil Kumar K V profile" loading="eager" />
160+
<div className="hero-image-card">
161+
<img src={HeroPic} alt="Sunil Kumar K V profile" loading="eager" />
162+
</div>
163+
</div>
164+
165+
<div className="hero-actions hero-actions-stage" aria-label="Primary actions">
166+
<Link to="/projects" className="hero-button">Explore Work</Link>
167+
<Link to="/dashboard" className="hero-button secondary">Open Dashboard</Link>
168+
<a href={profile.github} className="hero-button secondary" target="_blank" rel="noreferrer">GitHub</a>
107169
</div>
108170
</section>
109171

src/components/ui/AnimatedBackground.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@ import React, { useContext, useMemo } from "react";
22
import { ThemeContext } from "../../context/theme";
33
import "../../styles/AnimatedBackground.css";
44

5-
const codeSymbols = ["{ }", "< />", "=>", "fn()", "[]", "&&", "const", "git"];
5+
const codeSymbols = ["{}", "<>", "()", "[]", "λ"];
66

77
export default function AnimatedBackground() {
88
const { theme } = useContext(ThemeContext);
99

1010
const items = useMemo(
1111
() =>
12-
Array.from({ length: 12 }, (_, index) => ({
12+
Array.from({ length: 10 }, (_, index) => ({
1313
id: index,
1414
symbol: codeSymbols[index % codeSymbols.length],
15-
left: `${6 + index * 7.5}%`,
16-
delay: `${(index % 6) * 1.2}s`,
17-
duration: `${10 + (index % 5) * 2}s`,
15+
left: `${8 + index * 8.4}%`,
16+
delay: `${(index % 5) * 1.35}s`,
17+
duration: `${13 + (index % 4) * 2.6}s`,
1818
})),
1919
[]
2020
);
2121

2222
const sparkles = useMemo(
2323
() =>
24-
Array.from({ length: 14 }, (_, index) => ({
24+
Array.from({ length: 12 }, (_, index) => ({
2525
id: index,
26-
left: `${4 + index * 6.7}%`,
26+
left: `${5 + index * 7.4}%`,
2727
top: `${8 + (index % 5) * 18}%`,
28-
delay: `${(index % 7) * 0.8}s`,
29-
duration: `${8 + (index % 4) * 1.4}s`,
28+
delay: `${(index % 6) * 0.9}s`,
29+
duration: `${9 + (index % 4) * 1.8}s`,
3030
})),
3131
[]
3232
);

src/styles/AnimatedBackground.css

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
.bg-dark-glow {
1111
position: absolute;
1212
border-radius: 999px;
13-
filter: blur(40px);
14-
opacity: 0.32;
13+
filter: blur(46px);
14+
opacity: 0.24;
1515
}
1616

1717
.bg-light-blob {
18-
background: radial-gradient(circle, rgba(0, 123, 255, 0.18), rgba(0, 123, 255, 0));
18+
background: radial-gradient(circle, rgba(0, 123, 255, 0.13), rgba(0, 123, 255, 0));
1919
}
2020

2121
.bg-light-blob-a {
@@ -40,7 +40,7 @@
4040
}
4141

4242
.bg-dark-glow {
43-
background: radial-gradient(circle, rgba(0, 191, 255, 0.18), rgba(0, 191, 255, 0));
43+
background: radial-gradient(circle, rgba(0, 191, 255, 0.12), rgba(0, 191, 255, 0));
4444
}
4545

4646
.bg-dark-glow-a {
@@ -64,16 +64,16 @@
6464

6565
.bg-particle {
6666
position: absolute;
67-
width: 0.45rem;
68-
height: 0.45rem;
67+
width: 0.38rem;
68+
height: 0.38rem;
6969
border-radius: 999px;
70-
background: rgba(255, 255, 255, 0.14);
71-
box-shadow: 0 0 14px rgba(255, 255, 255, 0.08);
70+
background: rgba(255, 255, 255, 0.1);
71+
box-shadow: 0 0 12px rgba(255, 255, 255, 0.06);
7272
}
7373

7474
.bg-particles.light .bg-particle {
75-
background: rgba(0, 123, 255, 0.12);
76-
box-shadow: 0 0 12px rgba(0, 123, 255, 0.08);
75+
background: rgba(0, 123, 255, 0.08);
76+
box-shadow: 0 0 10px rgba(0, 123, 255, 0.06);
7777
}
7878

7979
.bg-code-rain {
@@ -84,9 +84,9 @@
8484
.bg-code-symbol {
8585
position: absolute;
8686
top: -10%;
87-
color: rgba(162, 220, 255, 0.08);
88-
font-size: 0.9rem;
89-
font-weight: 700;
87+
color: rgba(162, 220, 255, 0.06);
88+
font-size: 0.78rem;
89+
font-weight: 600;
9090
letter-spacing: 0.08em;
9191
white-space: nowrap;
9292
}
@@ -132,23 +132,23 @@
132132
0%,
133133
100% {
134134
transform: translate3d(0, 0, 0);
135-
opacity: 0.32;
135+
opacity: 0.24;
136136
}
137137
50% {
138138
transform: translate3d(0, 18px, 0);
139-
opacity: 0.34;
139+
opacity: 0.26;
140140
}
141141
}
142142

143143
@keyframes sparkleFloat {
144144
0%,
145145
100% {
146146
transform: translate3d(0, 0, 0) scale(0.9);
147-
opacity: 0.25;
147+
opacity: 0.18;
148148
}
149149
50% {
150150
transform: translate3d(0, -14px, 0) scale(1.12);
151-
opacity: 0.38;
151+
opacity: 0.28;
152152
}
153153
}
154154

@@ -158,10 +158,10 @@
158158
opacity: 0;
159159
}
160160
12% {
161-
opacity: 0.12;
161+
opacity: 0.08;
162162
}
163163
88% {
164-
opacity: 0.08;
164+
opacity: 0.05;
165165
}
166166
100% {
167167
transform: translate3d(0, 110vh, 0);

0 commit comments

Comments
 (0)