Skip to content

Commit 01c76e1

Browse files
jbingham17claude
andcommitted
Add mouse-reactive pulsating effects to CPU and memory graph dashboards
Graphs now respond to mouse hover with a radial glow that follows the cursor and pulsating animations on the chart area, values, core indicators, and memory bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 109c0ff commit 01c76e1

File tree

3 files changed

+153
-4
lines changed

3 files changed

+153
-4
lines changed

src/App.css

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,46 @@ body {
219219
/* Graph Cards */
220220
.cpu-graph,
221221
.memory-graph {
222+
--mouse-x: 50%;
223+
--mouse-y: 50%;
222224
background: var(--bg-card);
223225
border: 1px solid var(--border-color);
224226
border-radius: 12px;
225227
padding: 16px;
226228
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
227229
transition: border-color 0.3s, box-shadow 0.3s;
230+
position: relative;
231+
overflow: hidden;
232+
}
233+
234+
.cpu-graph::before,
235+
.memory-graph::before {
236+
content: '';
237+
position: absolute;
238+
top: 0;
239+
left: 0;
240+
right: 0;
241+
bottom: 0;
242+
background: radial-gradient(
243+
circle 200px at var(--mouse-x) var(--mouse-y),
244+
rgba(96, 165, 250, 0.12) 0%,
245+
transparent 70%
246+
);
247+
opacity: 0;
248+
transition: opacity 0.3s ease;
249+
pointer-events: none;
250+
z-index: 0;
251+
}
252+
253+
.cpu-graph > *,
254+
.memory-graph > * {
255+
position: relative;
256+
z-index: 1;
257+
}
258+
259+
.cpu-graph:hover::before,
260+
.memory-graph:hover::before {
261+
opacity: 1;
228262
}
229263

230264
.cpu-graph:hover,
@@ -233,6 +267,89 @@ body {
233267
box-shadow: 0 4px 30px rgba(96, 165, 250, 0.15);
234268
}
235269

270+
/* Pulsating graph effect on hover */
271+
.cpu-graph.graph-hovered .graph-container,
272+
.memory-graph.graph-hovered .graph-container {
273+
animation: graphPulsate 2s ease-in-out infinite;
274+
}
275+
276+
.cpu-graph.graph-hovered .graph-value,
277+
.memory-graph.graph-hovered .graph-value {
278+
animation: valuePulsate 1.5s ease-in-out infinite;
279+
}
280+
281+
.cpu-graph.graph-hovered .core-indicator {
282+
animation: corePulsate 2s ease-in-out infinite;
283+
}
284+
285+
.cpu-graph.graph-hovered .core-indicator:nth-child(odd) {
286+
animation-delay: 0.15s;
287+
}
288+
289+
.cpu-graph.graph-hovered .core-indicator:nth-child(3n) {
290+
animation-delay: 0.3s;
291+
}
292+
293+
.memory-graph.graph-hovered .memory-bar-fill {
294+
animation: barPulsate 1.8s ease-in-out infinite;
295+
}
296+
297+
.memory-graph.graph-hovered .memory-stat .stat-value {
298+
animation: valuePulsate 2s ease-in-out infinite;
299+
}
300+
301+
.memory-graph.graph-hovered .memory-stat:nth-child(2) .stat-value {
302+
animation-delay: 0.2s;
303+
}
304+
305+
.memory-graph.graph-hovered .memory-stat:nth-child(3) .stat-value {
306+
animation-delay: 0.4s;
307+
}
308+
309+
@keyframes graphPulsate {
310+
0%, 100% {
311+
filter: brightness(1) saturate(1);
312+
transform: scale(1);
313+
}
314+
50% {
315+
filter: brightness(1.3) saturate(1.4);
316+
transform: scale(1.01);
317+
}
318+
}
319+
320+
@keyframes valuePulsate {
321+
0%, 100% {
322+
opacity: 1;
323+
text-shadow: 0 0 20px currentColor;
324+
}
325+
50% {
326+
opacity: 0.8;
327+
text-shadow: 0 0 40px currentColor, 0 0 60px currentColor;
328+
}
329+
}
330+
331+
@keyframes corePulsate {
332+
0%, 100% {
333+
opacity: 1;
334+
transform: scale(1);
335+
}
336+
50% {
337+
opacity: 0.85;
338+
transform: scale(1.02);
339+
}
340+
}
341+
342+
@keyframes barPulsate {
343+
0%, 100% {
344+
filter: brightness(1);
345+
box-shadow: 0 0 20px currentColor;
346+
}
347+
50% {
348+
filter: brightness(1.4);
349+
box-shadow: 0 0 35px currentColor, 0 0 50px currentColor;
350+
}
351+
}
352+
236353
.graph-header {
237354
display: flex;
238355
justify-content: space-between;

src/components/CpuGraph.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect } from 'react';
1+
import { useState, useEffect, useRef, useCallback } from 'react';
22
import {
33
AreaChart,
44
Area,
@@ -36,6 +36,16 @@ const COLORS = [
3636

3737
export function CpuGraph({ cpuUsage }: CpuGraphProps) {
3838
const [history, setHistory] = useState<HistoryPoint[]>([]);
39+
const [isHovered, setIsHovered] = useState(false);
40+
const containerRef = useRef<HTMLDivElement>(null);
41+
42+
const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
43+
const rect = e.currentTarget.getBoundingClientRect();
44+
const x = ((e.clientX - rect.left) / rect.width) * 100;
45+
const y = ((e.clientY - rect.top) / rect.height) * 100;
46+
e.currentTarget.style.setProperty('--mouse-x', `${x}%`);
47+
e.currentTarget.style.setProperty('--mouse-y', `${y}%`);
48+
}, []);
3949

4050
useEffect(() => {
4151
const newPoint: HistoryPoint = { time: Date.now() };
@@ -57,7 +67,13 @@ export function CpuGraph({ cpuUsage }: CpuGraphProps) {
5767
: 0;
5868

5969
return (
60-
<div className="cpu-graph">
70+
<div
71+
className={`cpu-graph${isHovered ? ' graph-hovered' : ''}`}
72+
ref={containerRef}
73+
onMouseEnter={() => setIsHovered(true)}
74+
onMouseLeave={() => setIsHovered(false)}
75+
onMouseMove={handleMouseMove}
76+
>
6177
<div className="graph-header">
6278
<span className="graph-title">CPU</span>
6379
<span className="graph-value" style={{ color: getUsageColor(avgUsage) }}>

src/components/MemoryGraph.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect } from 'react';
1+
import { useState, useEffect, useRef, useCallback } from 'react';
22
import {
33
AreaChart,
44
Area,
@@ -32,6 +32,16 @@ function formatBytes(bytes: number): string {
3232

3333
export function MemoryGraph({ used, total, percent }: MemoryGraphProps) {
3434
const [history, setHistory] = useState<HistoryPoint[]>([]);
35+
const [isHovered, setIsHovered] = useState(false);
36+
const containerRef = useRef<HTMLDivElement>(null);
37+
38+
const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
39+
const rect = e.currentTarget.getBoundingClientRect();
40+
const x = ((e.clientX - rect.left) / rect.width) * 100;
41+
const y = ((e.clientY - rect.top) / rect.height) * 100;
42+
e.currentTarget.style.setProperty('--mouse-x', `${x}%`);
43+
e.currentTarget.style.setProperty('--mouse-y', `${y}%`);
44+
}, []);
3545

3646
useEffect(() => {
3747
const newPoint: HistoryPoint = {
@@ -59,7 +69,13 @@ export function MemoryGraph({ used, total, percent }: MemoryGraphProps) {
5969
const color = getMemoryColor(percent);
6070

6171
return (
62-
<div className="memory-graph">
72+
<div
73+
className={`memory-graph${isHovered ? ' graph-hovered' : ''}`}
74+
ref={containerRef}
75+
onMouseEnter={() => setIsHovered(true)}
76+
onMouseLeave={() => setIsHovered(false)}
77+
onMouseMove={handleMouseMove}
78+
>
6379
<div className="graph-header">
6480
<span className="graph-title">Memory</span>
6581
<span className="graph-value" style={{ color }}>

0 commit comments

Comments
 (0)