mirror of
https://github.com/harivansh-afk/React-Portfolio.git
synced 2026-04-15 05:02:11 +00:00
chore: add chart.js and react-chartjs-2 dependencies, update skills and work timeline in content options, and enhance about page styling
This commit is contained in:
parent
0383f88ba2
commit
eb6610e7d0
9 changed files with 544 additions and 87 deletions
30
package-lock.json
generated
30
package-lock.json
generated
|
|
@ -12,11 +12,13 @@
|
|||
"@types/node": "^22.13.10",
|
||||
"@types/react": "^19.0.11",
|
||||
"bootstrap": "^5.2.3",
|
||||
"chart.js": "^4.4.8",
|
||||
"clsx": "^2.1.1",
|
||||
"emailjs-com": "^3.2.0",
|
||||
"framer-motion": "^12.5.0",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.7.0",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-helmet-async": "^1.0.7",
|
||||
"react-icons": "^4.12.0",
|
||||
|
|
@ -3179,6 +3181,12 @@
|
|||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@kurkle/color": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
||||
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@leichtgewicht/ip-codec": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
|
||||
|
|
@ -5533,6 +5541,18 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/chart.js": {
|
||||
"version": "4.4.8",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz",
|
||||
"integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@kurkle/color": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/check-types": {
|
||||
"version": "11.2.2",
|
||||
"resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz",
|
||||
|
|
@ -13450,6 +13470,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-chartjs-2": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz",
|
||||
"integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"chart.js": "^4.1.1",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dev-utils": {
|
||||
"version": "12.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@
|
|||
"@types/node": "^22.13.10",
|
||||
"@types/react": "^19.0.11",
|
||||
"bootstrap": "^5.2.3",
|
||||
"chart.js": "^4.4.8",
|
||||
"clsx": "^2.1.1",
|
||||
"emailjs-com": "^3.2.0",
|
||||
"framer-motion": "^12.5.0",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.7.0",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-helmet-async": "^1.0.7",
|
||||
"react-icons": "^4.12.0",
|
||||
|
|
|
|||
140
src/components/SkillsRadar/index.js
Normal file
140
src/components/SkillsRadar/index.js
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Chart as ChartJS, RadialLinearScale, PointElement, LineElement, Filler, Tooltip, Legend } from 'chart.js';
|
||||
import { Radar } from 'react-chartjs-2';
|
||||
import './style.css';
|
||||
|
||||
// Register ChartJS components
|
||||
ChartJS.register(RadialLinearScale, PointElement, LineElement, Filler, Tooltip, Legend);
|
||||
|
||||
const SkillsRadar = ({ skills }) => {
|
||||
const [chartData, setChartData] = useState({
|
||||
labels: [],
|
||||
datasets: []
|
||||
});
|
||||
|
||||
// Set dark mode detection
|
||||
const [isDarkMode, setIsDarkMode] = useState(
|
||||
document.documentElement.getAttribute('data-theme') !== 'light'
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Watch for theme changes
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.attributeName === 'data-theme') {
|
||||
setIsDarkMode(document.documentElement.getAttribute('data-theme') !== 'light');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe(document.documentElement, { attributes: true });
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (skills && skills.length > 0) {
|
||||
// Get accent color from CSS vars
|
||||
const accentColor = 'rgba(204, 0, 0, 0.7)'; // Using the red accent
|
||||
|
||||
// Format data for the radar chart
|
||||
const data = {
|
||||
labels: skills.map(skill => skill.name),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Skill Proficiency',
|
||||
data: skills.map(skill => skill.value),
|
||||
backgroundColor: isDarkMode
|
||||
? 'rgba(204, 0, 0, 0.2)' // Slight red tint
|
||||
: 'rgba(204, 0, 0, 0.1)',
|
||||
borderColor: accentColor,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: isDarkMode
|
||||
? 'rgba(255, 255, 255, 1)'
|
||||
: 'rgba(0, 0, 0, 1)',
|
||||
pointBorderColor: accentColor,
|
||||
pointHoverBackgroundColor: accentColor,
|
||||
pointHoverBorderColor: isDarkMode ? '#fff' : '#000',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
setChartData(data);
|
||||
}
|
||||
}, [skills, isDarkMode]);
|
||||
|
||||
// Chart options
|
||||
const options = {
|
||||
scales: {
|
||||
r: {
|
||||
angleLines: {
|
||||
color: isDarkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
grid: {
|
||||
color: isDarkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
|
||||
},
|
||||
pointLabels: {
|
||||
color: isDarkMode ? 'rgba(255, 255, 255, 0.9)' : 'rgba(0, 0, 0, 0.9)',
|
||||
font: {
|
||||
size: 16,
|
||||
family: 'Raleway',
|
||||
weight: '600'
|
||||
},
|
||||
},
|
||||
ticks: {
|
||||
backdropColor: 'transparent',
|
||||
color: isDarkMode ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.7)',
|
||||
showLabelBackdrop: false,
|
||||
beginAtZero: true,
|
||||
max: 100,
|
||||
stepSize: 20,
|
||||
font: {
|
||||
size: 12
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top',
|
||||
labels: {
|
||||
color: isDarkMode ? '#fff' : '#000',
|
||||
font: {
|
||||
size: 14,
|
||||
family: 'Raleway',
|
||||
weight: 'bold'
|
||||
},
|
||||
boxWidth: 15,
|
||||
padding: 15
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: isDarkMode ? 'rgba(10, 10, 10, 0.9)' : 'rgba(255, 255, 255, 0.9)',
|
||||
titleColor: isDarkMode ? '#fff' : '#000',
|
||||
bodyColor: isDarkMode ? '#fff' : '#000',
|
||||
borderColor: 'rgba(204, 0, 0, 0.5)',
|
||||
borderWidth: 1,
|
||||
padding: 12,
|
||||
cornerRadius: 8,
|
||||
displayColors: false,
|
||||
callbacks: {
|
||||
title: (items) => items[0].label,
|
||||
label: (context) => `Proficiency: ${context.raw}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
responsive: true,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="skills-radar-container">
|
||||
<div className="skills-radar-chart">
|
||||
<Radar data={chartData} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkillsRadar;
|
||||
121
src/components/SkillsRadar/style.css
Normal file
121
src/components/SkillsRadar/style.css
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
.skills-radar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
opacity: 0;
|
||||
animation: fadeIn 0.8s ease-out forwards;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.skills-radar-chart {
|
||||
position: relative;
|
||||
height: 500px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.skills-legend {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.skill-legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: "Raleway", sans-serif;
|
||||
padding: 0.75rem 0.75rem;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
background-color: rgba(var(--secondary-rgb), 0.05);
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
animation: slideIn 0.5s ease-out forwards;
|
||||
}
|
||||
|
||||
.skill-legend-item:nth-child(1) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
.skill-legend-item:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
.skill-legend-item:nth-child(3) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
.skill-legend-item:nth-child(4) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
.skill-legend-item:nth-child(5) {
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
.skill-legend-item:nth-child(6) {
|
||||
animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.skill-legend-item:hover {
|
||||
background-color: rgba(var(--secondary-rgb), 0.1);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.skill-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.skill-legend-name {
|
||||
flex: 1;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.skill-legend-value {
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
opacity: 0.9;
|
||||
color: var(--text-color-3);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.skills-radar-chart {
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.skills-legend {
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
}
|
||||
|
||||
.skill-legend-name {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.skill-legend-value {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -20,94 +20,61 @@ const dataabout = {
|
|||
aboutme: "I am a Computer Science student at the University of Virginia, with a passion for software development and AI. I enjoy building scalable applications and exploring the latest advancements in technology. I am always eager to learn and contribute to innovative projects.",
|
||||
};
|
||||
const worktimeline = [{
|
||||
jobtitle: "Software Development Intern",
|
||||
where: "SUPPLMEN",
|
||||
date: "January 2025 - Present",
|
||||
url: "https://suppl-men.vercel.app/"
|
||||
},
|
||||
{
|
||||
jobtitle: "Co Founder",
|
||||
where: "SOLVEX",
|
||||
date: "December 2024 - Present",
|
||||
url: "https://solvex.live/"
|
||||
},
|
||||
{
|
||||
jobtitle: "Front End Development Intern",
|
||||
where: "UNIKOVE TECHNOLOGIES",
|
||||
date: "June 2024 - August 2024",
|
||||
url: "https://unikove.com/"
|
||||
},
|
||||
{
|
||||
jobtitle: "Software Development Intern",
|
||||
where: "MOGLIX",
|
||||
date: "June 2023 - August 2023",
|
||||
url: "https://www.moglix.com/"
|
||||
},
|
||||
{
|
||||
jobtitle: "Software Engineering Intern",
|
||||
where: "SAN AUTO",
|
||||
date: "June 2022 - August 2022",
|
||||
url: "https://www.sanautomotive.com/"
|
||||
},
|
||||
];
|
||||
|
||||
const skills = [{
|
||||
name: "Python",
|
||||
value: 90,
|
||||
},
|
||||
const skills = [
|
||||
{
|
||||
name: "Java",
|
||||
name: "Full-Stack Development",
|
||||
value: 85,
|
||||
},
|
||||
{
|
||||
name: "Typescript",
|
||||
value: 80,
|
||||
},
|
||||
{
|
||||
name: "HTML",
|
||||
name: "Frontend (React/Next.js)",
|
||||
value: 90,
|
||||
},
|
||||
{
|
||||
name: "CSS/Tailwind",
|
||||
name: "Backend (Node.js)",
|
||||
value: 88,
|
||||
},
|
||||
{
|
||||
name: "AI & Machine Learning",
|
||||
value: 85,
|
||||
},
|
||||
{
|
||||
name: "C/C++",
|
||||
value: 70,
|
||||
name: "Database & API Design",
|
||||
value: 85,
|
||||
},
|
||||
{
|
||||
name: "React.js",
|
||||
value: 80,
|
||||
},
|
||||
{
|
||||
name: "Node.js",
|
||||
value: 75,
|
||||
},
|
||||
{
|
||||
name: "Express.js",
|
||||
value: 75,
|
||||
},
|
||||
{
|
||||
name: "Vite",
|
||||
value: 80,
|
||||
},
|
||||
{
|
||||
name: "Next.js 14",
|
||||
value: 70,
|
||||
},
|
||||
{
|
||||
name: "Git/Github",
|
||||
value: 90,
|
||||
},
|
||||
{
|
||||
name: "PostgreSQL",
|
||||
value: 80,
|
||||
},
|
||||
{
|
||||
name: "MySQL",
|
||||
value: 80,
|
||||
},
|
||||
{
|
||||
name: "Supabase",
|
||||
value: 75,
|
||||
},
|
||||
{
|
||||
name: "Vercel",
|
||||
value: 80,
|
||||
},
|
||||
{
|
||||
name: "OAuth 2.0",
|
||||
value: 70,
|
||||
name: "DevOps & Deployment",
|
||||
value: 87,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@
|
|||
--overlay-color: rgb(8 8 8 / 63%);
|
||||
--image-container-bg: #060606;
|
||||
--card-border: rgba(255, 255, 255, 0.2);
|
||||
|
||||
/* RGB Values for opacity manipulation */
|
||||
--bg-color-rgb: 8, 8, 8;
|
||||
--primary-rgb: 15, 15, 15;
|
||||
--secondary-rgb: 255, 255, 255;
|
||||
--text-color-rgb: 255, 255, 255;
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
|
|
@ -20,6 +26,12 @@
|
|||
--overlay-color: rgb(227 218 201 / 70%);
|
||||
--image-container-bg: #d8c9b2;
|
||||
--card-border: rgba(0, 0, 0, 0.2);
|
||||
|
||||
/* RGB Values for opacity manipulation */
|
||||
--bg-color-rgb: 227, 218, 201;
|
||||
--primary-rgb: 227, 218, 201;
|
||||
--secondary-rgb: 0, 0, 0;
|
||||
--text-color-rgb: 0, 0, 0;
|
||||
}
|
||||
|
||||
html,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React from "react";
|
|||
import "./style.css";
|
||||
import { Helmet, HelmetProvider } from "react-helmet-async";
|
||||
import { Container, Row, Col } from "react-bootstrap";
|
||||
import { RiExternalLinkLine } from "react-icons/ri";
|
||||
import SkillsRadar from "../../components/SkillsRadar";
|
||||
import {
|
||||
dataabout,
|
||||
meta,
|
||||
|
|
@ -36,22 +38,39 @@ export const About = () => {
|
|||
</Row>
|
||||
<Row className=" sec_sp">
|
||||
<Col lg="5">
|
||||
<h3 className="color_sec py-4">Work Timline</h3>
|
||||
<h3 className="color_sec py-4">Work Timeline</h3>
|
||||
</Col>
|
||||
<Col lg="7">
|
||||
<table className="table caption-top">
|
||||
<tbody>
|
||||
{worktimeline.map((data, i) => {
|
||||
return (
|
||||
<tr key={i}>
|
||||
<th scope="row">{data.jobtitle}</th>
|
||||
<td>{data.where}</td>
|
||||
<td>{data.date}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="work-timeline">
|
||||
{worktimeline.map((data, i) => {
|
||||
return (
|
||||
<div key={i} className="timeline-item">
|
||||
<div className="timeline-content">
|
||||
<h4 className="timeline-title">{data.jobtitle}</h4>
|
||||
<div className="timeline-company">
|
||||
<span>{data.where}</span>
|
||||
{data.url && (
|
||||
<a
|
||||
href={data.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="company-link"
|
||||
aria-label={`Visit ${data.where} website`}
|
||||
title={`Visit ${data.where} website`}
|
||||
>
|
||||
<RiExternalLinkLine aria-hidden="true" />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<span className="timeline-date">{data.date}</span>
|
||||
{data.description && (
|
||||
<p className="timeline-description">{data.description}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="sec_sp">
|
||||
|
|
@ -76,24 +95,8 @@ export const About = () => {
|
|||
<Col lg="5">
|
||||
<h3 className="color_sec py-4">Skills</h3>
|
||||
</Col>
|
||||
<Col lg="7">
|
||||
{skills.map((data, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<h3 className="progress-title">{data.name}</h3>
|
||||
<div className="progress">
|
||||
<div
|
||||
className="progress-bar"
|
||||
style={{
|
||||
width: `${data.value}%`,
|
||||
}}
|
||||
>
|
||||
<div className="progress-value">{data.value}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<Col lg="7" className="d-flex justify-content-center">
|
||||
<SkillsRadar skills={skills} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
|
|
|
|||
|
|
@ -97,3 +97,168 @@
|
|||
transform: translateZ(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Work Timeline styling */
|
||||
.work-timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2.5rem;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
border-bottom: 1px solid rgba(var(--secondary-rgb), 0.2);
|
||||
padding-bottom: 2rem;
|
||||
transition: all 0.3s ease;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.timeline-item:hover {
|
||||
transform: translateX(8px);
|
||||
border-bottom-color: rgba(var(--secondary-rgb), 0.5);
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.timeline-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.timeline-item::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -1rem;
|
||||
top: 0.5rem;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(var(--secondary-rgb), 0.6);
|
||||
transform: scale(0);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.timeline-item:hover::before {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.timeline-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.timeline-company {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
margin: 0.25rem 0;
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.company-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
background: rgba(var(--secondary-rgb), 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(var(--text-color-rgb), 0.1);
|
||||
color: var(--text-color);
|
||||
font-size: 1rem;
|
||||
transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
margin-left: 0.5rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.company-link::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
var(--secondary) 0%,
|
||||
var(--text-color) 100%
|
||||
);
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s ease;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.company-link:hover,
|
||||
.company-link:focus {
|
||||
transform: translateY(-3px) scale(1.1);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
|
||||
color: var(--bg-color);
|
||||
}
|
||||
|
||||
.company-link:hover::before,
|
||||
.company-link:focus::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.company-link:active {
|
||||
transform: translateY(0) scale(0.95);
|
||||
}
|
||||
|
||||
.timeline-date {
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
margin: 0.25rem 0;
|
||||
color: var(--text-color);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.timeline-description {
|
||||
font-size: 0.95rem;
|
||||
margin-top: 0.75rem;
|
||||
line-height: 1.6;
|
||||
color: var(--text-color);
|
||||
opacity: 0.85;
|
||||
grid-column: 1 / -1;
|
||||
border-top: 1px solid rgba(var(--secondary-rgb), 0.1);
|
||||
padding-top: 0.75rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.timeline-content {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.timeline-title {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.timeline-company {
|
||||
grid-column: 2;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.timeline-date {
|
||||
grid-column: 3;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.timeline-description {
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
yarn.lock
17
yarn.lock
|
|
@ -1611,6 +1611,11 @@
|
|||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@kurkle/color@^0.3.0":
|
||||
version "0.3.4"
|
||||
resolved "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz"
|
||||
integrity sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==
|
||||
|
||||
"@leichtgewicht/ip-codec@^2.0.1":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz"
|
||||
|
|
@ -3106,6 +3111,13 @@ char-regex@^2.0.0:
|
|||
resolved "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz"
|
||||
integrity sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==
|
||||
|
||||
chart.js@^4.4.8:
|
||||
version "4.4.8"
|
||||
resolved "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz"
|
||||
integrity sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==
|
||||
dependencies:
|
||||
"@kurkle/color" "^0.3.0"
|
||||
|
||||
check-types@^11.1.1:
|
||||
version "11.2.2"
|
||||
resolved "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz"
|
||||
|
|
@ -7604,6 +7616,11 @@ react-bootstrap@^2.7.0:
|
|||
uncontrollable "^7.2.1"
|
||||
warning "^4.0.3"
|
||||
|
||||
react-chartjs-2@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz"
|
||||
integrity sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==
|
||||
|
||||
react-dev-utils@^12.0.1:
|
||||
version "12.0.1"
|
||||
resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue