1
0
mirror of https://github.com/XFox111/my-website.git synced 2026-04-22 07:28:01 +03:00

feat!: site refresh + dependency update

This commit is contained in:
2025-12-11 05:51:44 +00:00
parent aac9140830
commit 57b3a72fa2
48 changed files with 4943 additions and 1743 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
@include centerTwo;
> div:first-child
.content
{
@include flex(column);
gap: $spacingM;
+3 -3
View File
@@ -6,13 +6,13 @@ import cls from "./AboutSection.module.scss";
const AboutSection: React.FC = () => (
<section id="about" className={ cls.section }>
<div>
<Image src={ aboutPicture.src } alt={ aboutPicture.alt } />
<div className={ cls.content }>
<h2>About me</h2>
<Bio />
</div>
<Image src={ aboutPicture.src } alt={ aboutPicture.alt } />
</section>
);
+1 -1
View File
@@ -36,7 +36,7 @@ const ContactSection: React.FC = () =>
return (
<section id="contacts" className={ cls.section }>
<h2>Let&apos;s get in touch</h2>
<h2>Let&apos;s get in touch!</h2>
<div className={ cls.content }>
@@ -68,7 +68,7 @@
box-shadow: inset 0 0 0 16px $colorNeutralBackground1;
}
.description
.info
{
p
{
@@ -113,9 +113,16 @@
.item
{
grid-template-columns: 64px auto 1fr;
grid-template-rows: auto auto;
padding: $spacingXXXL $spacingNone;
gap: $spacingM;
align-items: center;
.description
{
grid-row: 2/2;
grid-column: 3/4;
}
}
}
@@ -126,7 +133,7 @@
.line
{
bottom: 72px;
bottom: 132px;
width: 100%;
height: 8px;
align-content: center;
@@ -147,9 +154,10 @@
.item
{
grid-template-rows: 128px auto 48px;
grid-template-rows: 128px auto 48px 48px;
padding: $spacingNone $spacingM;
row-gap: $spacingM;
cursor: pointer;
.year
{
@@ -171,6 +179,23 @@
}
.description
{
grid-row: 4/4;
transition-property: font-size, line-height, opacity;
transition-duration: $durationNormal;
transition-timing-function: $curveEasyEaseMax;
font-size: 0;
opacity: 0;
p
{
margin-bottom: $spacingSNudge;
}
}
.info
{
grid-row: 1/1;
align-self: self-end;
@@ -197,7 +222,7 @@
{
// Item that is being hovered or focused
&:is(:hover, :focus-visible, :focus-within)
&:is(:focus-visible, :focus-within)
{
.year,
@@ -207,16 +232,27 @@
opacity: 1;
}
> i
.description
{
box-shadow: inset 0 0 0 0 $colorNeutralBackground1;
@include body2($fontFamilyBaseAlt);
opacity: 1;
}
.description > p
.info > p
{
@include subtitle2($fontFamilyBaseAlt);
opacity: 1;
}
.year
{
font-size: $fontSizeHero800 !important;
}
}
&:is(:hover, :focus-visible, :focus-within) > i
{
box-shadow: inset 0 0 0 0 $colorNeutralBackground1;
}
// Other not focused items
@@ -228,8 +264,11 @@
{
@include body1($fontFamilyBaseAlt);
color: $colorNeutralForeground3;
}
@media screen and (max-width: 1200px)
@media screen and (max-width: 1200px)
{
.title
{
opacity: 0;
font-size: 0;
@@ -237,6 +276,18 @@
}
}
}
@media screen and (max-width: 1400px)
{
&:has(:focus-visible, :focus-within) .item:not(:focus-visible, :focus-within)
{
.title
{
opacity: 0;
font-size: 0;
}
}
}
}
}
}
+12 -5
View File
@@ -22,16 +22,23 @@ const ExperienceSection: React.FC = () => (
<div className={ cls.item } key={ index }
tabIndex={ 0 } role="listitem" aria-label={ getAriaLabel(i) }>
<p aria-hidden className={ cls.year }>{ i.year }</p>
<i />
<div className={ cls.description }>
{ i.description }
</div>
<p aria-hidden className={ cls.year } style={ index > 0 && experience[index - 1].year === i.year ? { fontSize: 0 } : undefined }>
{ i.year }
</p>
<i />
<div className={ cls.info }>
<p aria-hidden>{ i.place }</p>
<h3 aria-hidden className={ cls.title }>{ i.title }</h3>
<p aria-hidden={ !!i.tech }>{ i.tech ?? <Link href="#contacts">Contact me</Link> }</p>
<p aria-hidden={ !!i.summary }>{ i.summary ?? <Link href="#contacts">Contact me</Link> }</p>
</div>
</div>
) }
</div>
{/* <p>Deserunt esse irure duis magna irure. Eiusmod voluptate amet et elit adipisicing ut. Nulla minim elit anim mollit nisi amet est et magna veniam. Qui deserunt eiusmod laboris ex. Ex aute duis duis incididunt quis adipisicing dolor sit aliqua consectetur eu fugiat. Fugiat ipsum dolor elit ad commodo aliquip anim anim nostrud. Lorem adipisicing ex quis veniam aute amet cupidatat reprehenderit do laborum minim laboris sunt.</p> */}
</section>
);
@@ -47,8 +54,8 @@ function getAriaLabel(item: WorkplaceEntry): string
if (item.place)
str.push(`at ${item.place}`);
if (item.tech)
return str.join(" ") + `. ${item.tech}`;
if (item.summary)
return str.join(" ") + `. ${item.summary}`;
else
return str.join(" ");
+39 -8
View File
@@ -4,9 +4,16 @@
{
@include centerTwo;
.listItem
.content
{
background-position: right;
overflow-x: hidden;
gap: $spacingM;
@include flex(column);
.listItem
{
background-position-x: right;
}
}
.descriptions
@@ -16,12 +23,6 @@
overflow-x: visible;
min-height: 760px;
@media screen and (max-width: 860px)
{
min-height: unset;
padding-top: calc(56px + $spacingXL);
}
img
{
width: 100%;
@@ -35,6 +36,18 @@
@include slideIn;
}
.mobileNav
{
margin-top: $spacingL;
display: none;
gap: $spacingMNudge;
.next
{
flex-grow: 1;
}
}
.projectItem
{
@include flex(column);
@@ -96,4 +109,22 @@
{
align-self: flex-end;
}
@media screen and (max-width: 860px)
{
.descriptions
{
min-height: unset;
.mobileNav
{
display: flex;
}
}
.list
{
display: none;
}
}
}
+36 -15
View File
@@ -5,7 +5,9 @@ import Button from "@/_components/Button";
import links from "@/_data/links";
import projects from "@/_data/projects";
import shared from "@/_styles/gallery.module.scss";
import { ArrowRight24Regular } from "@fluentui/react-icons";
import ArrowRight24Regular from "@fluentui/svg-icons/icons/arrow_right_24_regular.svg";
import ChevronLeft24Regular from "@fluentui/svg-icons/icons/chevron_left_24_regular.svg";
import ChevronRight24Regular from "@fluentui/svg-icons/icons/chevron_right_24_regular.svg";
import Image from "next/image";
import React, { useCallback, useState } from "react";
import { networkFor } from "react-social-icons";
@@ -23,23 +25,25 @@ const ProjectsSection: React.FC = () =>
return (
<section id="projects" className={ cls.section }>
<div className={ shared.list }>
<div className={ cls.content }>
<h2>My pet projects</h2>
{ projects.map((project, index) =>
<Button key={ index } type="button"
className={ `${shared.listItem} ${cls.listItem}` }
appearance={ selection === index ? "primary" : "secondary" }
data-selected={ selection === index }
onClick={ () => select(selection == index ? undefined : index) }
aria-label={ `"${project.title}". ${project.subtitle}` }>
<div className={ `${shared.list} ${cls.list}` }>
{ projects.map((project, index) =>
<Button key={ index } type="button"
className={ `${shared.listItem} ${cls.listItem}` }
appearance={ selection === index ? "primary" : "secondary" }
data-selected={ selection === index }
onClick={ () => select(selection == index ? undefined : index) }
aria-label={ `"${project.title}". ${project.subtitle}` }>
<div className={ shared.content }>
<span className={ shared.title }>{ project.title }</span>
<span>{ project.subtitle }</span>
</div>
</Button>
) }
<div className={ shared.content }>
<span className={ shared.title }>{ project.title }</span>
<span>{ project.subtitle }</span>
</div>
</Button>
) }
</div>
<Button className={ cls.cta } appearance="secondary" href={ links.github } target="_blank"
iconAfter={ <ArrowRight24Regular /> }>
@@ -85,6 +89,23 @@ const ProjectsSection: React.FC = () =>
) }
<Image className={ cls.defaultImg } hidden={ selection !== undefined }
src={ projectsImg.src } alt={ projectsImg.alt } loading="eager" />
<div className={ cls.mobileNav }>
<Button type="button"
icon={ <ChevronLeft24Regular /> }
aria-label="Previous project"
disabled={ selection === undefined }
onClick={ () => setSelection(selection! < 1 ? undefined : selection! - 1) } />
{ (selection ?? -1) < projects.length - 1 &&
<Button type="button" className={ cls.next }
icon={ <ChevronRight24Regular /> }
onClick={ () => setSelection((selection ?? -1) + 1) } >
Next project: { projects[(selection ?? -1) + 1].title }
</Button>
}
</div>
</div>
</section>
);
+106 -12
View File
@@ -9,14 +9,48 @@
.illustrations
{
justify-self: center;
position: relative;
width: 100%;
img
.item
{
width: 100%;
max-height: 600px;
position: relative;
@include flex(column);
gap: $spacingXXXL;
@include slideIn;
img
{
align-self: flex-end;
max-height: 400px;
width: auto;
max-width: 100%;
height: auto;
}
h3
{
@include subtitle1($fontFamilyBaseAlt);
display: none;
}
p
{
@include subtitle1($fontFamilyBaseAlt);
}
}
.mobileNav
{
margin-top: $spacingM;
display: none;
gap: $spacingMNudge;
.next
{
flex-grow: 1;
background-position-x: right;
}
}
// [SPECIAL]
@@ -25,28 +59,88 @@
position: absolute;
cursor: pointer;
bottom: calc(50% - 20px + 13.5%);
left: 40%;
width: 20%;
height: 40px;
right: 214px;
top: 81px;
width: 60px;
height: 25px;
@media screen and (max-width: 1400px)
@media screen and (max-width: 573px)
{
bottom: calc(50% - 20px + 6vw)
right: calc(50% - 30px);
top: calc(15vw - 7px);
}
}
// [SPECIAL]
.sus
{
position: absolute;
cursor: pointer;
left: 0;
top: 200px;
width: 90px;
height: 100px;
@media screen and (max-width: 1472px)
{
top: calc(15vw - 20px);
width: calc(8vw - 24px);
height: calc(8vw - 17px);
@media screen and (max-width: 860px)
{
top: calc(35vw - 65px);
width: 12vw;
height: 14vw;
}
}
}
}
.list
.content
{
@include flex(column);
gap: $spacingM;
.cta
{
align-self: flex-end;
}
}
@media screen and (max-width: 860px)
@media screen and (max-width: 860px)
{
.content
{
grid-row: 1;
.list
{
display: none;
}
}
.illustrations
{
.mobileNav
{
display: flex;
}
.item
{
h3
{
display: block;
}
p
{
@include subtitle2($fontFamilyBaseAlt);
}
}
}
}
}
+67 -30
View File
@@ -1,13 +1,15 @@
"use client";
import Button from "@/_components/Button";
import links from "@/_data/links";
import skills from "@/_data/skills";
import shared from "@/_styles/gallery.module.scss";
import { ArrowDownload24Regular } from "@fluentui/react-icons";
import ArrowDownload24Regular from "@fluentui/svg-icons/icons/arrow_download_24_regular.svg";
import ChevronLeft24Regular from "@fluentui/svg-icons/icons/chevron_left_24_regular.svg";
import ChevronRight24Regular from "@fluentui/svg-icons/icons/chevron_right_24_regular.svg";
import Image from "next/image";
import React, { useCallback, useId, useState } from "react";
import cls from "./SkillsSection.module.scss";
import links from "@/_data/links";
const SkillsSection: React.FC = () =>
{
@@ -24,39 +26,74 @@ const SkillsSection: React.FC = () =>
<section id="skills" className={ cls.section }>
<div id={ illustrations } className={ cls.illustrations } aria-live="polite" aria-atomic>
{ skills.map((i, index) =>
<Image key={ index }
src={ i.image.src } alt={ i.image.alt }
hidden={ selection !== index } loading="eager" />
<div key={ index } className={ cls.item } hidden={ selection !== index }>
<Image src={ i.image.src } alt={ i.image.alt } loading="eager" />
<h3>{ i.title }</h3>
<p>{ i.description }</p>
{ selection === 4 &&
// [SPECIAL] It's a surprize tool that will help us later
<div role="button" aria-label="Click me"
className={ cls.whatsThis }
onClick={ () =>
{
window.clarity?.("event", "ngguu");
window.open("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
} } />
}
{ selection === 7 &&
// [SPECIAL] sus
<div role="button" aria-label="Click me"
className={ cls.sus }
onClick={ () =>
{
window.clarity?.("event", "sus");
const track = new Audio("sus.mp3");
track.volume = 0.1;
track.play();
} } />
}
</div>
) }
{ selection === 4 &&
// [SPECIAL] It's a surprize tool that will help us later
<div role="button" aria-label="Click me"
className={ cls.whatsThis }
onClick={ () =>
{
window.clarity?.("event", "ngguu");
window.open("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
} } />
}
<div className={ cls.mobileNav }>
<Button type="button"
icon={ <ChevronLeft24Regular /> }
aria-label="Previous skill"
disabled={ selection < 1 }
onClick={ () => setSelection(selection - 1) } />
{ selection < skills.length - 1 &&
<Button type="button" className={ cls.next }
icon={ <ChevronRight24Regular /> }
onClick={ () => setSelection(selection + 1) } >
Next skill: { skills[selection + 1].title }
</Button>
}
</div>
</div>
<div className={ `${shared.list} ${cls.list}` }>
<h2>My skillset</h2>
<div className={ cls.content }>
<h2>My skills &amp; tools</h2>
{ skills.map((skill, index) =>
<Button key={ index } type="button" aria-current={ selection === index } aria-controls={ illustrations }
className={ shared.listItem } appearance={ selection === index ? "primary" : "secondary" }
data-selected={ selection === index }
onClick={ () => select(index) }
aria-label={ `${skill.title} skills. Associated stack: ${skill.description}` }
icon={ <skill.icon /> } >
<div className={ `${shared.list} ${cls.list}` }>
{ skills.map((skill, index) =>
<Button key={ index } type="button" aria-current={ selection === index } aria-controls={ illustrations }
className={ shared.listItem } appearance={ selection === index ? "primary" : "secondary" }
data-selected={ selection === index }
onClick={ () => select(index) }
aria-label={ `${skill.title} skills. Associated stack: ${skill.caption}` }
icon={ <skill.icon /> } >
<div className={ shared.content }>
<span className={ shared.title }>{ skill.title }</span>
<span>{ skill.description }</span>
</div>
</Button>
) }
<div className={ shared.content }>
<span className={ shared.title }>{ skill.title }</span>
<span>{ skill.caption }</span>
</div>
</Button>
) }
</div>
<Button appearance="secondary" className={ cls.cta }
as="next" href={ links.resume }