feat: enhance SkillsRadar component with mobile optimizations, including responsive design adjustments and improved label display for better usability on smaller screens

This commit is contained in:
Harivansh Rathi 2025-03-21 11:48:07 -04:00
parent eb6610e7d0
commit ae63547831
3 changed files with 87 additions and 10 deletions

View file

@ -17,6 +17,9 @@ const SkillsRadar = ({ skills }) => {
document.documentElement.getAttribute('data-theme') !== 'light' document.documentElement.getAttribute('data-theme') !== 'light'
); );
// Check if the device is mobile
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
useEffect(() => { useEffect(() => {
// Watch for theme changes // Watch for theme changes
const observer = new MutationObserver((mutations) => { const observer = new MutationObserver((mutations) => {
@ -29,7 +32,17 @@ const SkillsRadar = ({ skills }) => {
observer.observe(document.documentElement, { attributes: true }); observer.observe(document.documentElement, { attributes: true });
return () => observer.disconnect(); // Watch for resize events to detect mobile
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => {
observer.disconnect();
window.removeEventListener('resize', handleResize);
};
}, []); }, []);
useEffect(() => { useEffect(() => {
@ -69,17 +82,45 @@ const SkillsRadar = ({ skills }) => {
r: { r: {
angleLines: { angleLines: {
color: isDarkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)', color: isDarkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)',
lineWidth: isMobile ? 0.5 : 1
}, },
grid: { grid: {
color: isDarkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)', color: isDarkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
circular: true,
lineWidth: isMobile ? 0.5 : 1
}, },
pointLabels: { pointLabels: {
color: isDarkMode ? 'rgba(255, 255, 255, 0.9)' : 'rgba(0, 0, 0, 0.9)', color: isDarkMode ? 'rgba(255, 255, 255, 0.9)' : 'rgba(0, 0, 0, 0.9)',
font: { font: {
size: 16, size: isMobile ? 10 : 16,
family: 'Raleway', family: 'Raleway',
weight: '600' weight: '600'
}, },
// Improve label display on mobile
callback: function(value) {
if (isMobile) {
// Create mobile-friendly abbreviations
switch(value) {
case "Full-Stack Development":
return "Full-Stack";
case "Frontend (React/Next.js)":
return "Frontend";
case "Backend (Node.js)":
return "Backend";
case "AI & Machine Learning":
return "AI & ML";
case "Database & API Design":
return "Database";
case "DevOps & Deployment":
return "DevOps";
default:
return value;
}
}
return value;
},
// Ensure labels don't get cut off
padding: isMobile ? 8 : 4,
}, },
ticks: { ticks: {
backdropColor: 'transparent', backdropColor: 'transparent',
@ -87,16 +128,20 @@ const SkillsRadar = ({ skills }) => {
showLabelBackdrop: false, showLabelBackdrop: false,
beginAtZero: true, beginAtZero: true,
max: 100, max: 100,
stepSize: 20, stepSize: isMobile ? 25 : 20,
font: { font: {
size: 12 size: isMobile ? 8 : 12
} },
// Display fewer ticks on mobile
count: isMobile ? 4 : 6,
// Make sure the scale starts at 50
min: 50
}, },
}, },
}, },
plugins: { plugins: {
legend: { legend: {
display: true, display: !isMobile, // Hide legend on mobile to save space
position: 'top', position: 'top',
labels: { labels: {
color: isDarkMode ? '#fff' : '#000', color: isDarkMode ? '#fff' : '#000',
@ -115,13 +160,15 @@ const SkillsRadar = ({ skills }) => {
bodyColor: isDarkMode ? '#fff' : '#000', bodyColor: isDarkMode ? '#fff' : '#000',
borderColor: 'rgba(204, 0, 0, 0.5)', borderColor: 'rgba(204, 0, 0, 0.5)',
borderWidth: 1, borderWidth: 1,
padding: 12, padding: isMobile ? 8 : 12,
cornerRadius: 8, cornerRadius: 8,
displayColors: false, displayColors: false,
callbacks: { callbacks: {
title: (items) => items[0].label, title: (items) => items[0].label,
label: (context) => `Proficiency: ${context.raw}%`, label: (context) => `Proficiency: ${context.raw}%`,
}, },
// Ensure tooltip doesn't go off-screen on mobile
position: 'nearest',
}, },
}, },
maintainAspectRatio: false, maintainAspectRatio: false,

View file

@ -102,9 +102,21 @@
color: var(--text-color-3); color: var(--text-color-3);
} }
/* Mobile Optimizations */
@media (max-width: 768px) { @media (max-width: 768px) {
.skills-radar-container {
max-width: 100%;
padding: 0;
overflow: visible;
}
.skills-radar-chart { .skills-radar-chart {
height: 350px; height: 380px;
margin: 0 auto;
width: 100vw;
max-width: 100vw;
transform: scale(0.95);
transform-origin: center center;
} }
.skills-legend { .skills-legend {
@ -119,3 +131,21 @@
font-size: 0.9rem; font-size: 0.9rem;
} }
} }
/* Small Mobile Optimizations */
@media (max-width: 480px) {
.skills-radar-chart {
height: 340px;
transform: scale(0.9);
margin-left: -15px;
margin-right: -15px;
}
}
/* Extra Small Mobile Optimizations */
@media (max-width: 375px) {
.skills-radar-chart {
height: 320px;
transform: scale(0.85);
}
}

View file

@ -92,10 +92,10 @@ export const About = () => {
</Col> </Col>
</Row> </Row>
<Row className="sec_sp"> <Row className="sec_sp">
<Col lg="5"> <Col lg="5" className="mb-3 mb-lg-0">
<h3 className="color_sec py-4">Skills</h3> <h3 className="color_sec py-4">Skills</h3>
</Col> </Col>
<Col lg="7" className="d-flex justify-content-center"> <Col lg="7" xs="12" className="d-flex justify-content-center align-items-center px-0">
<SkillsRadar skills={skills} /> <SkillsRadar skills={skills} />
</Col> </Col>
</Row> </Row>