From d0e6637551c1ecdac0b91fadcc9fe553fa2fd9dd Mon Sep 17 00:00:00 2001 From: Karim Hossenbux Date: Mon, 25 Mar 2024 19:48:58 +0100 Subject: [PATCH] highlight skill on hover --- components/HighlightedSkills.js | 16 ++++++ components/Item.js | 13 +++++ components/Skills.js | 32 ++++++----- components/Work.js | 26 +++++---- data/resume.json | 99 ++++++++++++++++++++++++++------- pages/index.js | 28 +++++----- 6 files changed, 153 insertions(+), 61 deletions(-) create mode 100644 components/HighlightedSkills.js diff --git a/components/HighlightedSkills.js b/components/HighlightedSkills.js new file mode 100644 index 0000000..9ea4eb5 --- /dev/null +++ b/components/HighlightedSkills.js @@ -0,0 +1,16 @@ +import { useState } from 'react'; +import Work from './Work'; +import Skills from './Skills'; + +const HighlightedSkills = (props) => { + const [highlightedSkill, setHighlightedSkill] = useState(null); + + return ( +
+ + +
+ ); +}; + +export default HighlightedSkills; diff --git a/components/Item.js b/components/Item.js index b280264..3a068ca 100644 --- a/components/Item.js +++ b/components/Item.js @@ -1,11 +1,24 @@ import Link from 'next/link'; const Item = (props) => { + const handleMouseEnter = () => { + if (props?.setHighlightedSkills) { + props.setHighlightedSkills(props?.skills); + } + }; + + const handleMouseLeave = () => { + if (props?.setHighlightedSkills) { + props.setHighlightedSkills(null); + } + }; return (
diff --git a/components/Skills.js b/components/Skills.js index 4078a85..b5b8c69 100644 --- a/components/Skills.js +++ b/components/Skills.js @@ -1,32 +1,36 @@ -import Link from 'next/link' -import Title from './Title' - -const Skills = (props) => { - const items = props.items +import Title from './Title'; +const Skills = ({ items, highlightedSkills }) => { return (
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>`} /> + <Title + title="Skills" + icon={`<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>`} + /> <div className="md:flex justify-between pl-4"> - {items.map((item, index) => + {items.map((item, index) => ( <div className="md:w-1/3 px-4 mb-4 md:mb-0" key={index}> <h3 className="text-xs font-semibold uppercase mb-1"> {item.name} </h3> - {item.keywords.map((keyword, kindex) => + {item.keywords.map((keyword, kindex) => ( <span - className="inline-flex mr-2 text-xs font-semibold text-opacity-70 text-black border px-1 rounded border-purple-100 bg-purple-50 dark:border-gray-900 dark:bg-gray-600" + className={`inline-flex mr-2 text-xs font-semibold text-opacity-70 text-black border px-1 rounded border-purple-100 dark:border-gray-900 transition-colors ${ + highlightedSkills?.includes(keyword) + ? 'bg-green-400' + : 'dark:bg-gray-600 bg-purple-50' + }`} key={kindex} > {keyword} </span> - )} + ))} </div> - )} + ))} </div> </div> - ) -} + ); +}; -export default Skills \ No newline at end of file +export default Skills; diff --git a/components/Work.js b/components/Work.js index d164cdd..16a2272 100644 --- a/components/Work.js +++ b/components/Work.js @@ -1,16 +1,16 @@ -import Link from 'next/link' -import Title from './Title' -import Item from './Item' - -const Work = (props) => { - const items = props.items +import Title from './Title'; +import Item from './Item'; +const Work = ({ items, setHighlightedSkills }) => { return ( <div className="section"> - <Title title="Experiences" icon={`<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg>`} /> + <Title + title="Experiences" + icon={`<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg>`} + /> <div className="pl-8"> - {items.map((item, index) => + {items.map((item, index) => ( <Item key={index} title={item.position} @@ -19,11 +19,13 @@ const Work = (props) => { startDate={item.startDate} endDate={item.endDate} content={item.summary} + skills={item.skills} + setHighlightedSkills={setHighlightedSkills} /> - )} + ))} </div> </div> - ) -} + ); +}; -export default Work \ No newline at end of file +export default Work; diff --git a/data/resume.json b/data/resume.json index d4a6e72..b36bb33 100644 --- a/data/resume.json +++ b/data/resume.json @@ -45,14 +45,35 @@ "website": "https://www.ef.com", "skills": [ "TypeScript", + "JavaScript", "React", + "RSC", "Next.js", "Tailwind", + "SCSS", + "Vue", + "CSS/SVG Animation", + "UI/UX", + "p5.js", + "Jest", + "Cypress", + "Serverless", + "Architect Serverless", + "AWS SAM", + "Terraform", + "Lambda", + "S3", + "CloudFront", + "Headless CMS (Storyblok)", + "API", + "Node", + "PHP", "Storyblok", "AWS", "Serverless", - "API", - "RESTful" + "RESTful", + "Figma", + "JIRA" ] }, { @@ -65,7 +86,14 @@ "Launched and oversaw operations for a Shopify e-commerce platform tailored to developers, offering a large range of merchandise.", "Fun side project to get better at design and marketing." ], - "website": "https://merch.dev" + "website": "https://merch.dev", + "skills": [ + "JavaScript", + "Node", + "Shopify", + "Figma", + "Sketch" + ] }, { "company": "Moonitor.io", @@ -77,7 +105,19 @@ "Developed a cryptocurrency portfolio tracker compatible with macOS, Windows, and Linux, currently expanding to iOS/Android using React Native.", "Managed all aspects of the app, including development, design, sales/licensing, and support." ], - "website": "https://moonitor.io" + "website": "https://moonitor.io", + "skills": [ + "TypeScript", + "JavaScript", + "React", + "Next.js", + "React Native", + "Tailwind", + "Electron", + "Prisma", + "PostgreSQL", + "Figma" + ] }, { "company": "Game Publishing / Exoty", @@ -88,7 +128,16 @@ "summary": [ "Managed a network of 400+ gambling websites, implementing over 100 sites from scratch based on stakeholder requirements." ], - "website": "https://www.exoty.com" + "website": "https://www.exoty.com", + "skills": [ + "JavaScript", + "SCSS", + "CSS/SVG Animation", + "UI/UX", + "MySQL", + "PHP", + "Laravel" + ] }, { "company": "Maria Barcelona", @@ -100,7 +149,15 @@ "Implemented new features on various client websites, including Liceu Theatre, Knorr, and Moventis.", "Contributed to both front-end and back-end development tasks." ], - "website": "https://mariabarcelona.com/" + "website": "https://mariabarcelona.com/", + "skills": [ + "JavaScript", + "SCSS", + "CSS/SVG Animation", + "UI/UX", + "MySQL", + "PHP" + ] }, { "company": "Cmedia", @@ -112,7 +169,15 @@ "Managed a network of 1200+ gambling websites using WordPress, Drupal, and dynamic/static stack.", "Developed a centralized backend for serving dynamic contents, widgets and ads across all networks." ], - "website": "https://cmedia.es" + "website": "https://cmedia.es", + "skills": [ + "JavaScript", + "SCSS", + "CSS/SVG Animation", + "UI/UX", + "MySQL", + "PHP" + ] } ], "volunteer": [ @@ -132,27 +197,21 @@ "area": "English degree", "studyType": "Licence", "startDate": "2006/12", - "endDate": "2008/12", - "gpa": "", - "courses": [] + "endDate": "2008/12" }, { "institution": "Lycée de Bellepierre", "area": "BTS - Application Development and Systems Integration", "studyType": "Computer Science", "startDate": "2004/12", - "endDate": "2006/12", - "gpa": "", - "courses": [] + "endDate": "2006/12" }, { "institution": "Lycée Antoine Roussin", "area": "Baccalauréat in Tertiary Sciences and Technologies", "studyType": "Computer Science", "startDate": "2004/12", - "endDate": "2002/12", - "gpa": "", - "courses": [] + "endDate": "2002/12" } ], "skills": [ @@ -165,6 +224,7 @@ "Next.js", "React Native", "Tailwind", + "SCSS", "Nuxt.js", "Vuex", "Vue", @@ -173,10 +233,7 @@ "UI/UX", "p5.js", "Jest", - "Cypress", - "HTML", - "SCSS", - "CSS" + "Cypress" ], "name": "Frontend" }, @@ -190,12 +247,12 @@ "S3", "CloudFront", "Headless CMS (Storyblok)", + "Prisma", "PostgreSQL", "MySQL", "Node", "PHP", "Laravel", - "API", "RESTful" ], "name": "Backend" diff --git a/pages/index.js b/pages/index.js index ff61870..dc8e7f5 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,16 +1,17 @@ -import Head from 'next/head' -import DarkMode from '../components/DarkMode' -import About from '../components/About' -import Work from '../components/Work' -import Skills from '../components/Skills' -import Educations from '../components/Educations' -import Languages from '../components/Languages' -import Interests from '../components/Interests' -import Footer from '../components/Footer' -import { getResume } from '../utils/resume' +import Head from 'next/head'; +import DarkMode from '../components/DarkMode'; +import About from '../components/About'; +import Work from '../components/Work'; +import Skills from '../components/Skills'; +import HighlightedSkills from '../components/HighlightedSkills'; +import Educations from '../components/Educations'; +import Languages from '../components/Languages'; +import Interests from '../components/Interests'; +import Footer from '../components/Footer'; +import { getResume } from '../utils/resume'; export default function Home() { - const resume = getResume() + const resume = getResume(); return ( <div className="relative"> @@ -24,8 +25,7 @@ export default function Home() { <main className="mb-12"> <About info={resume.basics} /> - <Skills items={resume.skills} /> - <Work items={resume.work} /> + <HighlightedSkills skills={resume.skills} works={resume.work} /> <Educations items={resume.education} /> <Languages items={resume.languages} /> <Interests items={resume.interests} /> @@ -34,5 +34,5 @@ export default function Home() { <Footer /> </div> </div> - ) + ); }