From 6d0b6326ecc13222f18f4a2ec9db436ec5e3cf5e Mon Sep 17 00:00:00 2001 From: Tal Jacob Date: Sun, 13 Apr 2025 23:31:49 +0300 Subject: [PATCH] Add Gauge Gradient Color Transitions Signed-off-by: Tal Jacob --- nextstep-frontend/package.json | 1 + .../src/components/ScoreGauge.tsx | 60 +++++++++++++++++++ nextstep-frontend/src/pages/Resume.tsx | 36 +---------- 3 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 nextstep-frontend/src/components/ScoreGauge.tsx diff --git a/nextstep-frontend/package.json b/nextstep-frontend/package.json index a2838ff..3f86cd3 100644 --- a/nextstep-frontend/package.json +++ b/nextstep-frontend/package.json @@ -15,6 +15,7 @@ "@mui/icons-material": "^6.4.7", "@mui/joy": "^5.0.0-beta.51", "@mui/material": "^6.4.3", + "@mui/x-charts": "^7.28.0", "@types/axios": "^0.9.36", "@types/react-router-dom": "^5.3.3", "axios": "^1.7.9", diff --git a/nextstep-frontend/src/components/ScoreGauge.tsx b/nextstep-frontend/src/components/ScoreGauge.tsx new file mode 100644 index 0000000..0193bd9 --- /dev/null +++ b/nextstep-frontend/src/components/ScoreGauge.tsx @@ -0,0 +1,60 @@ +import * as React from 'react'; +import { Gauge, gaugeClasses } from '@mui/x-charts/Gauge'; +import { Box } from '@mui/material'; + +interface ScoreGaugeProps { + score: number; + width?: number; + height?: number; +} + +const ScoreGauge: React.FC = ({ score, width = 200, height = 200 }) => { + const getGradientColor = (value: number) => { + // Clamp value between 0 and 100 + value = Math.max(0, Math.min(100, value)); + + let r, g, b; + + if (value <= 50) { + // Red (255, 0, 0) to Yellow (255, 215, 0) + const ratio = value / 50; + r = 255; + g = Math.round(215 * ratio); + b = 0; + } else { + // Yellow (255, 215, 0) to Green (82, 178, 2) + const ratio = (value - 50) / 50; + r = Math.round(255 + (82 - 255) * ratio); // Decrease red + g = Math.round(215 + (178 - 215) * ratio); // Shift green + b = Math.round(0 + (2 - 0) * ratio); // Increase blue a little + } + + return `rgb(${r}, ${g}, ${b})`; + }; + + return ( + + ({ + [`& .${gaugeClasses.valueText}`]: { + fontSize: 30, + fontWeight: 'bold', + }, + [`& .${gaugeClasses.valueArc}`]: { + fill: getGradientColor(score), + transition: 'fill 1s ease-in-out', + }, + [`& .${gaugeClasses.referenceArc}`]: { + fill: theme.palette.text.disabled, + }, + })} + /> + + ); +}; + +export default ScoreGauge; \ No newline at end of file diff --git a/nextstep-frontend/src/pages/Resume.tsx b/nextstep-frontend/src/pages/Resume.tsx index c51db44..498e78c 100644 --- a/nextstep-frontend/src/pages/Resume.tsx +++ b/nextstep-frontend/src/pages/Resume.tsx @@ -5,6 +5,7 @@ import { config } from '../config'; import api from '../serverApi'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; +import ScoreGauge from '../components/ScoreGauge'; const UploadBox = styled(Box)(({ theme }) => ({ border: '2px dashed #ccc', @@ -17,35 +18,6 @@ const UploadBox = styled(Box)(({ theme }) => ({ }, })); -const ScoreGauge = styled(Box)<{ score: number }>(({ theme }) => ({ - width: '200px', - height: '200px', - borderRadius: '50%', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - background: `conic-gradient( - ${theme.palette.error.main} 0% 33%, - ${theme.palette.warning.main} 33% 66%, - ${theme.palette.success.main} 66% 100% - )`, - position: 'relative', - '&::before': { - content: '""', - position: 'absolute', - width: '180px', - height: '180px', - borderRadius: '50%', - background: theme.palette.background.paper, - }, -})); - -const ScoreText = styled(Typography)({ - position: 'absolute', - fontSize: '2.5rem', - fontWeight: 'bold', -}); - const FeedbackContainer = styled(Box)(({ theme }) => ({ maxHeight: '60vh', overflowY: 'auto', @@ -243,10 +215,8 @@ const Resume: React.FC = () => { )} {score !== null && ( - - - {score} - + + )}