feat: stricter lint, check pipelines, docker-containers, pnpm

This commit is contained in:
2026-02-22 17:48:51 +00:00
parent 40ca6ef94a
commit b697ad823a
50 changed files with 4976 additions and 5431 deletions

View File

@@ -5,7 +5,7 @@ import Achievements from "@/src/portfolio/sections/Achievements";
import Footer from "@/src/portfolio/sections/Footer";
import SkillsAndLinks from "@/src/portfolio/sections/SkillsAndLinks";
const MainPage = () => {
const MainPage = (): JSX.Element => {
return (
<div>
<Intro/>
@@ -18,4 +18,4 @@ const MainPage = () => {
);
};
export default MainPage;
export default MainPage;

View File

@@ -1,4 +1,4 @@
import {AwardArgs} from "@/src/portfolio/helpers/Certificate";
import { AwardArgs } from "@/src/portfolio/helpers/Certificate";
const certificateData : AwardArgs[] = [
{
@@ -16,21 +16,21 @@ const certificateData : AwardArgs[] = [
city: "Warsaw",
awardDate: "July 2020",
notes: [
"Overall: 7.5 / 9.0, equivalent to C1",
"Overall: 7.5 / 9.0, equivalent to C1"
]
},
{
title: "Project Management Fundamentals",
institution: "Project Management Institute",
city: "Warsaw",
awardDate: "April 2019",
awardDate: "April 2019"
},
{
title: "Project Management Principles",
institution: "Project Management Institute",
city: "Warsaw",
awardDate: "April 2019",
awardDate: "April 2019"
}
];
export default certificateData;
export default certificateData;

View File

@@ -1,4 +1,4 @@
import {EducationArgs} from "@/src/portfolio/helpers/Education";
import { EducationArgs } from "@/src/portfolio/helpers/Education";
const educationData : EducationArgs[] = [
{
@@ -39,8 +39,8 @@ const educationData : EducationArgs[] = [
"Final exam in Physics: 97% percentile",
"Final exam in Mathematics: 92% percentile"
],
useWith: true, //todo fix this (i.e. this does nothing)
useWith: true //todo fix this (i.e. this does nothing)
}
];
export default educationData;
export default educationData;

View File

@@ -63,4 +63,4 @@ export const modulesTaken : {
level: "UG",
score: 86
}
];
];

View File

@@ -1,6 +1,6 @@
import {ProjectArguments, SkillEnum} from "@/src/portfolio/helpers/Project";
import { IProjectArguments, SkillEnum } from "@/src/portfolio/helpers/Project";
const projectData : ProjectArguments[] = [
const projectData : IProjectArguments[] = [
{
imagePath: "expertAgents.png",
tech: [
@@ -55,7 +55,7 @@ const projectData : ProjectArguments[] = [
title: "Natural Computing: Implementing and analysis of PSO, GA and GP",
tech: [
SkillEnum.python,
SkillEnum.numpy,
SkillEnum.numpy
],
text: "During my Master's program, I had the opportunity to take a course on Natural Computing, where I implemented and analyzed three major algorithms: Particle Swarm Optimization (PSO), Genetic Algorithms (GA), and Genetic Programming (GP). This coursework allowed me to gain hands-on experience with these powerful optimization techniques, which are inspired by natural phenomena such as swarm intelligence and evolution. Through this project, I developed a deep understanding of the underlying principles of natural computing and its potential applications in various fields, such as engineering, finance, and biology. I am excited to showcase my implementation and analysis of PSO, GA, and GP on my website and demonstrate my proficiency in natural computing techniques.",
github: "https://github.com/KuchtaVR6/nat_coursework",
@@ -70,7 +70,7 @@ const projectData : ProjectArguments[] = [
SkillEnum.react,
SkillEnum.html,
SkillEnum.css,
SkillEnum.express,
SkillEnum.express
],
github: "https://github.com/KuchtaVR6/Learnopedia"
},
@@ -148,7 +148,13 @@ const projectData : ProjectArguments[] = [
// {
// imagePath: "port1.png",
// title: "My previous portfolio website",
// text: "This website was created as a challenge to myself to create an eye-pleasing and portable website with limited time. I decided to make it purely using HTML and CSS, and for the portability, I have used Bootstrap CSS. The resulting product is an informative, simple and good looking portfolio, which I was quite happy with. Throughout this academic year, I have gained more confidence in using React, I have decided to remake my portfolio this time with a more interesting and responsive design in mind, whilst maintaining the readability of the older version.",
// text: "This website was created as a challenge to myself to create an eye-pleasing " +
// "and portable website with limited time. I decided to make it purely using HTML and CSS, " +
// "and for the portability, I have used Bootstrap CSS. The resulting product is an " +
// "informative, simple and good looking portfolio, which I was quite happy with. " +
// "Throughout this academic year, I have gained more confidence in using React, I have " +
// "decided to remake my portfolio this time with a more interesting and responsive design " +
// "in mind, whilst maintaining the readability of the older version.",
// tech: [
// SkillEnum.html,
// SkillEnum.css,
@@ -177,11 +183,17 @@ const projectData : ProjectArguments[] = [
SkillEnum.linux,
SkillEnum.design3d
]
},
}
// {
// imagePath: "port3.png",
// title: "My current portfolio website",
// text: "And finally, this website is my most recent project. Design-wise I wanted to keep the website minimalistic but stunning at the same time to show my skills, and I have kept accessibility in mind. I had created this project with plentiful react to experience and I created this website with a very high standard of code and with reusability in mind so that I don't have to rewrite this website in the future. Admittedly I will probably end up doing it anyway because I love coding and improving my websites. ",
// text: "And finally, this website is my most recent project. Design-wise I wanted to " +
// "keep the website minimalistic but stunning at the same time to show my skills, and I " +
// "have kept accessibility in mind. I had created this project with plentiful react to " +
// "experience and I created this website with a very high standard of code and with " +
// "reusability in mind so that I don't have to rewrite this website in the future. " +
// "Admittedly I will probably end up doing it anyway because I love coding and " +
// "improving my websites. ",
// tech: [
// SkillEnum.react,
// SkillEnum.html,
@@ -193,4 +205,4 @@ const projectData : ProjectArguments[] = [
// }
];
export default projectData;
export default projectData;

View File

@@ -1,5 +1,5 @@
import {SkillEnum} from "@/src/portfolio/helpers/Project";
import {ProficiencyLevel} from "@/src/portfolio/helpers/SkillDisplay";
import { SkillEnum } from "@/src/portfolio/helpers/Project";
import { ProficiencyLevel } from "@/src/portfolio/helpers/SkillDisplay";
export const skillsInCategories = {
"Programming Languages": [

View File

@@ -1,4 +1,4 @@
import {WorkExperienceArgs} from "@/src/portfolio/helpers/WorkExperience";
import { WorkExperienceArgs } from "@/src/portfolio/helpers/WorkExperience";
const workExperienceData : WorkExperienceArgs[] = [
{
@@ -97,7 +97,7 @@ const workExperienceData : WorkExperienceArgs[] = [
country: "Poland",
startDate: "July 2018",
endDate: "August 2018"
},
}
];
export const workExperienceParagraph =
@@ -114,4 +114,4 @@ export const workExperienceParagraph =
"working on several AI projects, applying my theoretical machine learning knowledge to real-world problems. " +
"Across these diverse roles, I have developed a strong work ethic and a broad set of transferable skills.";
export default workExperienceData;
export default workExperienceData;

View File

@@ -1,15 +1,15 @@
import React, {FC, useState} from "react";
import React, { FC, useState } from "react";
import { CSSTransition } from "react-transition-group";
type args = {
type AccordionArgs = {
title : string,
children : React.ReactNode,
}
const Accordion : FC<args> = ({ title, children }) => {
const Accordion : FC<AccordionArgs> = ({ title, children }): JSX.Element => {
const [isOpen, setIsOpen] = useState(false);
const toggleAccordion = () => {
const toggleAccordion = (): void => {
setIsOpen(!isOpen);
};

View File

@@ -1,4 +1,4 @@
import {FC} from "react";
import { FC } from "react";
import styles from "../styling/achievements.module.scss";
export type AwardArgs = {
@@ -11,7 +11,7 @@ export type AwardArgs = {
const Award : FC<AwardArgs> = (props) => {
const getCountryEmoji = () => {
const getCountryEmoji = (): string => {
switch (props.city) {
case "Warsaw":
return ", PL";
@@ -48,4 +48,4 @@ const Award : FC<AwardArgs> = (props) => {
);
};
export default Award;
export default Award;

View File

@@ -1,4 +1,4 @@
import {FC} from "react";
import { FC } from "react";
import styles from "../styling/achievements.module.scss";
export type EducationArgs = {
@@ -14,7 +14,7 @@ export type EducationArgs = {
const Education : FC<EducationArgs> = (props) => {
const getCountryEmoji = () => {
const getCountryEmoji = (): string => {
switch (props.city) {
case "Warsaw":
return ", Poland";
@@ -26,7 +26,7 @@ const Education : FC<EducationArgs> = (props) => {
};
return (
<div style={{fontSize: "1.1em"}} className={styles.education} data-aos={"fade-right"}>
<div style={{ fontSize: "1.1em" }} className={styles.education} data-aos={"fade-right"}>
<div>
<span className={styles.title}>{props.title}</span> in <b>{props.subtitle}</b>
<br/>
@@ -48,10 +48,10 @@ const Education : FC<EducationArgs> = (props) => {
{props.endDate ?
<>
<i>From:&nbsp;&nbsp;</i>
<span style={{float:"right"}}>{props.startDate}</span>
<span style={{ float:"right" }}>{props.startDate}</span>
<br/>
<i>To:&nbsp;&nbsp;</i>
<span style={{float:"right"}}>{props.endDate}</span>
<span style={{ float:"right" }}>{props.endDate}</span>
</>:
"Since " + props.startDate
}
@@ -60,4 +60,4 @@ const Education : FC<EducationArgs> = (props) => {
);
};
export default Education;
export default Education;

View File

@@ -1,28 +1,27 @@
import {FC, MutableRefObject, useEffect, useRef, useState} from "react";
import { FC, MutableRefObject, useEffect, useRef, useState } from "react";
type args = {
type ProgressBarArgs = {
percentage : number,
customScore? : string,
}
const ProgressBar : FC<args> = ({percentage,customScore}) => {
const ProgressBar : FC<ProgressBarArgs> = ({ percentage,customScore }): JSX.Element => {
const ref = useRef<HTMLDivElement>() as MutableRefObject<HTMLDivElement>;
const onScreen = useOnScreen(ref);
const [current,setCurrent] = useState(0);
useEffect(()=>{
if(onScreen && current==0)
useEffect(() => {
if (onScreen && current==0)
{
let counter = 0;
const id = setInterval(() => {
if(counter<percentage*2)
if (counter<percentage*2)
{
counter += (percentage/100);
setCurrent(counter);
}
else{
if(counter>percentage*2)
else {
if (counter>percentage*2)
{
setCurrent(percentage*2);
}
@@ -30,20 +29,20 @@ const ProgressBar : FC<args> = ({percentage,customScore}) => {
}
},25);
}
},[onScreen]);
},[onScreen, current, percentage]);
return (
<div className={"pBContainer"} ref={ref}>
<div className={"progressBar"}>
<div className={"inner"} style={{width : `${current/2}%`}}></div>
<div className={"inner"} style={{ width : `${current/2}%` }}></div>
</div>
<div className={"below"} style={{width : customScore? "100%" : `${current/2}%`, textAlign: "right"}}>{customScore? customScore : Math.ceil(current/2)+"%"}</div>
<div className={"below"} style={{ width : customScore? "100%" : `${current/2}%`, textAlign: "right" }}>{customScore? customScore : Math.ceil(current/2)+"%"}</div>
</div>
);
};
function useOnScreen(ref : MutableRefObject<HTMLDivElement>, rootMargin = "0px") {
function useOnScreen(ref : MutableRefObject<HTMLDivElement>, rootMargin = "0px"): boolean {
// State and setter for storing whether element is visible
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
@@ -53,22 +52,25 @@ function useOnScreen(ref : MutableRefObject<HTMLDivElement>, rootMargin = "0px")
setIntersecting(entry.isIntersecting);
},
{
rootMargin,
rootMargin
}
);
if (ref.current) {
observer.observe(ref.current);
const currentRef = ref.current;
if (currentRef) {
observer.observe(currentRef);
}
return () => {
try{
observer.unobserve(ref.current);
}
catch (e) {
console.log("REPORTED: observer failure :/");
if (currentRef) {
try {
observer.unobserve(currentRef);
}
catch {
// Observer failure handled silently
}
}
};
}, []); // Empty array ensures that effect is only run on mount and unmount
}, [ref, rootMargin]);
return isIntersecting;
}
export default ProgressBar;
export default ProgressBar;

View File

@@ -1,9 +1,9 @@
import Image from "next/image";
import styles from "../styling/projects.module.scss";
import {VscGithub} from "react-icons/vsc";
import {BsGlobe2, BsFileEarmarkMedical} from "react-icons/bs";
import { VscGithub } from "react-icons/vsc";
import { BsGlobe2, BsFileEarmarkMedical } from "react-icons/bs";
export interface ProjectArguments {
export interface IProjectArguments {
imagePath : string,
title : string,
text : string,
@@ -47,7 +47,7 @@ export enum SkillEnum {
english = "English",
}
const Project = ({imagePath, title, text, github, access, document} : ProjectArguments) => {
const Project = ({ imagePath, title, text, github, access, document } : IProjectArguments): JSX.Element => {
return (
<div className={styles.projectDisplay}>
<div className={styles.text}>
@@ -92,4 +92,4 @@ const Project = ({imagePath, title, text, github, access, document} : ProjectArg
);
};
export default Project;
export default Project;

View File

@@ -1,8 +1,8 @@
import {FC} from "react";
import { FC } from "react";
import styles from "../styling/projects.module.scss";
import {SkillEnum} from "@/src/portfolio/helpers/Project";
import { SkillEnum } from "@/src/portfolio/helpers/Project";
type args = {
type SkillDisplayArgs = {
name : SkillEnum,
level? : ProficiencyLevel,
}
@@ -15,8 +15,7 @@ export enum ProficiencyLevel {
master = "Master",
}
const SkillDisplay : FC<args> = ({name, level}) => {
const SkillDisplay : FC<SkillDisplayArgs> = ({ name, level }): JSX.Element => {
const level_to_emoji = {
[ProficiencyLevel.beginner]: "🌱",
[ProficiencyLevel.intermediate]: "🌳",
@@ -29,7 +28,7 @@ const SkillDisplay : FC<args> = ({name, level}) => {
return (
<div id={name.toLowerCase()} className={styles.technology}>
<b>{name}&nbsp;&nbsp;</b>
<span style={{float: "right", fontSize: "0.8em"}}>{level} {level_to_emoji[level]}</span>
<span style={{ float: "right", fontSize: "0.8em" }}>{level} {level_to_emoji[level]}</span>
</div>
);
}
@@ -40,4 +39,4 @@ const SkillDisplay : FC<args> = ({name, level}) => {
);
};
export default SkillDisplay;
export default SkillDisplay;

View File

@@ -1,4 +1,4 @@
import {FC} from "react";
import { FC } from "react";
import styles from "../styling/experience.module.scss";
export type WorkExperienceArgs = {
@@ -13,7 +13,7 @@ export type WorkExperienceArgs = {
const WorkExperience : FC<WorkExperienceArgs> = (props) => {
const getEmojiForIndustry = () => {
const getEmojiForIndustry = (): string | undefined => {
switch (props.industry) {
case "Education":
return "🎓";
@@ -43,4 +43,4 @@ const WorkExperience : FC<WorkExperienceArgs> = (props) => {
);
};
export default WorkExperience;
export default WorkExperience;

View File

@@ -4,7 +4,7 @@ import styles from "../styling/achievements.module.scss";
import educationData from "@/src/portfolio/data/educationData";
import certificateData from "@/src/portfolio/data/certificateData";
const Achievements = () => {
const Achievements = (): JSX.Element => {
return (
<div className={styles.section} id={"achievements"}>
<div>
@@ -27,4 +27,4 @@ const Achievements = () => {
);
};
export default Achievements;
export default Achievements;

View File

@@ -1,11 +1,11 @@
import {Splide, SplideSlide} from "@splidejs/react-splide";
import {useEffect, useState} from "react";
import { Splide, SplideSlide } from "@splidejs/react-splide";
import { useEffect, useState } from "react";
import styles from "../styling/experience.module.scss";
import WorkExperience from "@/src/portfolio/helpers/WorkExperience";
import workExperienceData, {workExperienceParagraph} from "@/src/portfolio/data/workExperienceData";
import workExperienceData, { workExperienceParagraph } from "@/src/portfolio/data/workExperienceData";
const Experience = () => {
const calcPagesOnWidth = (width : number) => {
const Experience = (): JSX.Element => {
const calcPagesOnWidth = (width : number): number => {
return Math.floor(width / 800 + 1);
};
@@ -14,7 +14,7 @@ const Experience = () => {
useEffect(() => {
setPages(calcPagesOnWidth(window.innerWidth));
const handleResize = () => {
const handleResize = (): void => {
setPages(calcPagesOnWidth(window.innerWidth));
};
@@ -53,4 +53,4 @@ const Experience = () => {
);
};
export default Experience;
export default Experience;

View File

@@ -1,6 +1,6 @@
import styles from "../styling/footer.module.scss";
const Footer = () => {
const Footer = (): JSX.Element => {
return (
<footer className={styles.section}>
Copyright &copy; Patryk Kuchta {new Date().getFullYear()}
@@ -8,4 +8,4 @@ const Footer = () => {
);
};
export default Footer;
export default Footer;

View File

@@ -1,65 +0,0 @@
import styles from "../styling/intro.module.scss";
import Image from "next/image";
import profilePic from "../../../public/portfolio/profile.png";
import logo from "../../../public/portfolio/logo.svg";
const Intro = () => {
const greeting = () => {
const hour = new Date().getHours();
if (hour > 4 && hour < 12) {
return "Good Morning!";
} else if (hour < 18) {
return "Good Afternoon!";
} else {
return "Good Evening!";
}
};
return (
<section className={styles.section}>
<header className={styles.topBar} data-aos={"zoom-in-down"} data-aos-duration={"500"}>
<div className={styles.row}>
<div className={styles.logoContainer}>
<Image src={logo} alt={"Kuchta logo"} fill={true}/>
</div>
<a href={"#achievements"}>Achievements</a>
<a href={"#experience"}>Experience</a>
<a href={"#projects"}>Projects</a>
<a href={"#skills"}>Skills</a>
</div>
<div className={styles.left}>
<a href={"mailto: patrick@kuchta.uk"}>patrick@kuchta.uk</a>
<span>/</span>
<a href={"mailto: patryk@kuchta.uk"}>patryk@kuchta.uk</a>
</div>
</header>
<div className={styles.mainContent}>
<div className={styles.text} data-aos={"fade-in"} data-aos-duration={"500"}>
<div className={styles.larger}>
<span className={styles.greeting}>
{greeting()}
</span>
<br/>
I am
<b> Patryk Kuchta, </b>
an aspiring
<br/>
<b>Artificial Intelligence Scientist</b>.
</div>
<span data-aos={"fade-in"} data-aos-offset={"200"}><i>and yes, the greeting is synced to your time.</i></span>
</div>
<div className={styles.profileContainer}>
<Image
src={profilePic}
alt={"Frontal image showing Patryk Kuchta"}
fill={true}
/>
</div>
</div>
</section>
);
};
export default Intro;

View File

@@ -0,0 +1,17 @@
import styles from "../../styling/intro.module.scss";
import TopBar from "./TopBar";
import IntroContent from "./IntroContent";
import { getGreeting } from "./helpers";
const Intro = (): JSX.Element => {
const greeting = getGreeting();
return (
<section className={styles.section}>
<TopBar/>
<IntroContent greeting={greeting}/>
</section>
);
};
export default Intro;

View File

@@ -0,0 +1,39 @@
import Image from "next/image";
import styles from "../../styling/intro.module.scss";
import profilePic from "../../../../public/portfolio/profile.png";
interface IIntroContentProps {
greeting: string;
}
const IntroContent = ({ greeting }: IIntroContentProps): JSX.Element => {
return (
<div className={styles.mainContent}>
<div className={styles.text} data-aos={"fade-in"} data-aos-duration={"500"}>
<div className={styles.larger}>
<span className={styles.greeting}>
{greeting}
</span>
<br/>
I am
<b> Patryk Kuchta, </b>
an aspiring
<br/>
<b>Artificial Intelligence Scientist</b>.
</div>
<span data-aos={"fade-in"} data-aos-offset={"200"}>
<i>and yes, the greeting is synced to your time.</i>
</span>
</div>
<div className={styles.profileContainer}>
<Image
src={profilePic}
alt={"Frontal image showing Patryk Kuchta"}
fill={true}
/>
</div>
</div>
);
};
export default IntroContent;

View File

@@ -0,0 +1,26 @@
import Image from "next/image";
import styles from "../../styling/intro.module.scss";
import logo from "../../../../public/portfolio/logo.svg";
const TopBar = (): JSX.Element => {
return (
<header className={styles.topBar} data-aos={"zoom-in-down"} data-aos-duration={"500"}>
<div className={styles.row}>
<div className={styles.logoContainer}>
<Image src={logo} alt={"Kuchta logo"} fill={true}/>
</div>
<a href={"#achievements"}>Achievements</a>
<a href={"#experience"}>Experience</a>
<a href={"#projects"}>Projects</a>
<a href={"#skills"}>Skills</a>
</div>
<div className={styles.left}>
<a href={"mailto: patrick@kuchta.uk"}>patrick@kuchta.uk</a>
<span>/</span>
<a href={"mailto: patryk@kuchta.uk"}>patryk@kuchta.uk</a>
</div>
</header>
);
};
export default TopBar;

View File

@@ -0,0 +1,10 @@
export const getGreeting = (): string => {
const hour = new Date().getHours();
if (hour > 4 && hour < 12) {
return "Good Morning!";
} else if (hour < 18) {
return "Good Afternoon!";
} else {
return "Good Evening!";
}
};

View File

@@ -0,0 +1 @@
export { default } from "./Intro";

View File

@@ -1,16 +1,16 @@
import {Splide, SplideSlide} from "@splidejs/react-splide";
import { Splide, SplideSlide } from "@splidejs/react-splide";
import Project from "@/src/portfolio/helpers/Project";
import projectData from "@/src/portfolio/data/projectData";
import styles from "../styling/projects.module.scss";
const Projects = () => {
const Projects = (): JSX.Element => {
return (
<div className={styles.section} id={"projects"}>
<Splide
options={{
rewind: true,
type: "slide",
perPage: 1,
perPage: 1
}}
>
{ projectData.map((entry, key) => {
@@ -24,4 +24,4 @@ const Projects = () => {
);
};
export default Projects;
export default Projects;

View File

@@ -1,107 +1 @@
import styles from "../styling/skillsLinks.module.scss";
import SkillDisplay from "@/src/portfolio/helpers/SkillDisplay";
import Accordion from "@/src/portfolio/helpers/Accordion";
import {skillsInCategories} from "@/src/portfolio/data/skillsData";
import {modulesTaken} from "@/src/portfolio/data/modulesTaken";
const SkillsAndLinks = () => {
const moreInfoLinks = [
{
title: "Github",
link: "https://github.com/KuchtaVR6/"
},
{
title: "LinkedIn",
link: "https://linkedin.com/in/kuchtap"
},
{
title: "Curriculum Vitae",
link: "/PatrykKuchta_CV.pdf"
}
];
const contactLinks = [
{
title: "Email",
link: "mailto:patryk@kuchta.uk"
},
{
title: "LinkedIn",
link: "https://linkedin.com/in/kuchtap"
}
];
return (
<div className={styles.section} id={"skills"}>
<div data-aos = {"fade-left"} className={styles.skills}>
<div>
<i>Press the &quot;+&quot; to expand a section</i>&nbsp;👀
</div>
<div className={styles.innerskills}>
{
Object.entries(skillsInCategories).map(([category, skills]) => {
console.log(skills);
return <Accordion title={category} key={category}>
{
skills.map((skill) => {
return <SkillDisplay {...skill} key={skill.name} />;
})
}
</Accordion>;
})
}
<Accordion title={"Modules Taken"}>
{
modulesTaken.map(({name, level, score}) => {
return <div id={name.toLowerCase()}
className={styles.technology}
key={name}>
<b>{name}&nbsp;&nbsp;</b>
<span style={{float: "right", fontSize: "0.8em"}}>
{score>=0? score + "%" : "🔮"} <i>{level}</i>
</span>
</div>;
})
}
</Accordion>
</div>
</div>
<div data-aos = {"fade-right"} className={styles.otherLinks}>
<h2>Find out more about me:</h2>
<ul>
{
moreInfoLinks.map(({title, link}, key) => {
return (
<li key = {key}>
<a href={link}>
{title}
</a>
</li>
);
}
)
}
</ul>
<h2>Contact me through:</h2>
<ul>
{
contactLinks.map(({title, link}, key) => {
return (
<li key = {key}>
<a href={link}>
{title}
</a>
</li>
);
}
)
}
</ul>
</div>
</div>
);
};
export default SkillsAndLinks;
export { default } from "./SkillsAndLinks/SkillsAndLinks";

View File

@@ -0,0 +1,71 @@
import styles from "../../styling/skillsLinks.module.scss";
interface ILink {
title: string;
link: string;
}
const moreInfoLinks: ILink[] = [
{
title: "Github",
link: "https://github.com/KuchtaVR6/"
},
{
title: "LinkedIn",
link: "https://linkedin.com/in/kuchtap"
},
{
title: "Curriculum Vitae",
link: "/PatrykKuchta_CV.pdf"
}
];
const contactLinks: ILink[] = [
{
title: "Email",
link: "mailto:patryk@kuchta.uk"
},
{
title: "LinkedIn",
link: "https://linkedin.com/in/kuchtap"
}
];
const LinksSection = (): JSX.Element => {
return (
<div data-aos = {"fade-right"} className={styles.otherLinks}>
<h2>Find out more about me:</h2>
<ul>
{
moreInfoLinks.map(({ title, link }, key) => {
return (
<li key = {key}>
<a href={link}>
{title}
</a>
</li>
);
}
)
}
</ul>
<h2>Contact me through:</h2>
<ul>
{
contactLinks.map(({ title, link }, key) => {
return (
<li key = {key}>
<a href={link}>
{title}
</a>
</li>
);
}
)
}
</ul>
</div>
);
};
export default LinksSection;

View File

@@ -0,0 +1,14 @@
import styles from "../../styling/skillsLinks.module.scss";
import SkillsSection from "./SkillsSection";
import LinksSection from "./LinksSection";
const SkillsAndLinks = (): JSX.Element => {
return (
<div className={styles.section} id={"skills"}>
<SkillsSection/>
<LinksSection/>
</div>
);
};
export default SkillsAndLinks;

View File

@@ -0,0 +1,45 @@
import styles from "../../styling/skillsLinks.module.scss";
import SkillDisplay from "@/src/portfolio/helpers/SkillDisplay";
import Accordion from "@/src/portfolio/helpers/Accordion";
import { skillsInCategories } from "@/src/portfolio/data/skillsData";
import { modulesTaken } from "@/src/portfolio/data/modulesTaken";
const SkillsSection = (): JSX.Element => {
return (
<div data-aos = {"fade-left"} className={styles.skills}>
<div>
<i>Press the &quot;+&quot; to expand a section</i>&nbsp;👀
</div>
<div className={styles.innerskills}>
{
Object.entries(skillsInCategories).map(([category, skills]) => {
return <Accordion title={category} key={category}>
{
skills.map((skill) => {
return <SkillDisplay {...skill} key={skill.name} />;
})
}
</Accordion>;
})
}
<Accordion title={"Modules Taken"}>
{
modulesTaken.map(({ name, level, score }) => {
return <div id={name.toLowerCase()}
className={styles.technology}
key={name}>
<b>{name}&nbsp;&nbsp;</b>
<span style={{ float: "right", fontSize: "0.8em" }}>
{score>=0? score + "%" : "🔮"} <i>{level}</i>
</span>
</div>;
})
}
</Accordion>
</div>
</div>
);
};
export default SkillsSection;

View File

@@ -0,0 +1 @@
export { default } from "./SkillsAndLinks";