Project page added + Overall Improvements
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 278 KiB |
@@ -1,5 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import {useRef, useState, useEffect} from "react";
|
import {useRef, useState, useEffect} from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default function About() {
|
export default function About() {
|
||||||
const timelineData = [
|
const timelineData = [
|
||||||
@@ -149,6 +150,8 @@ export default function About() {
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
scrollBehavior: "smooth",
|
scrollBehavior: "smooth",
|
||||||
|
scrollbarWidth: "none", // Firefox
|
||||||
|
msOverflowStyle: "none", // IE/Edge
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{timelineData.map((item, index) => (
|
{timelineData.map((item, index) => (
|
||||||
@@ -220,6 +223,23 @@ export default function About() {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{marginTop: "3rem"}}>
|
||||||
|
<Link href="/projects">
|
||||||
|
<button
|
||||||
|
className="learnMoreButton"
|
||||||
|
style={{
|
||||||
|
padding: "1rem 2rem",
|
||||||
|
fontSize: "1.25rem",
|
||||||
|
border: "none",
|
||||||
|
borderRadius: "5px",
|
||||||
|
color: "#fff",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
View Projects
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -129,6 +129,13 @@ html {
|
|||||||
background-color: #2e002e;
|
background-color: #2e002e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes pulsePrompt {
|
||||||
|
0% { opacity: 0.6; transform: translateY(0); }
|
||||||
|
50% { opacity: 1; transform: translateY(-5px); }
|
||||||
|
100% { opacity: 0.6; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.scrollPrompt {
|
.scrollPrompt {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
@@ -140,6 +147,7 @@ html {
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
background: none;
|
background: none;
|
||||||
|
animation: pulsePrompt 2s infinite ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-in-section.is-visible {
|
.fade-in-section.is-visible {
|
||||||
@@ -151,6 +159,13 @@ html {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.learnMoreButton:hover {
|
||||||
|
background-color: #2e002e;
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 0 10px #600060;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
@@ -193,3 +208,71 @@ body {
|
|||||||
transform: translateY(8px);
|
transform: translateY(8px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.section {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.projectContainer {
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 2rem;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projectCard {
|
||||||
|
max-width: 800px;
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 2px solid #3d003d;
|
||||||
|
background-color: rgba(20, 0, 20, 0.4);
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projectImage {
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
border: 4px solid #3d003d;
|
||||||
|
animation: pulseBorder 1.5s infinite alternate ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projectNavigation {
|
||||||
|
margin-top: 2rem;
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowButton {
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
background-color: #3d003d;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowButton:hover {
|
||||||
|
background-color: #2e002e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-in {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-out {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-7
@@ -10,17 +10,21 @@ export default function Home() {
|
|||||||
const [title, setTitle] = useState("Fretux");
|
const [title, setTitle] = useState("Fretux");
|
||||||
const [phase, setPhase] = useState("normal");
|
const [phase, setPhase] = useState("normal");
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
let fadeTimeout;
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
setPhase("fadeOut");
|
setPhase("fadeOut");
|
||||||
setTimeout(() => {
|
fadeTimeout = setTimeout(() => {
|
||||||
setTitle((prev) => (prev === "Fretux" ? "Frederik Spirgi" : "Fretux"));
|
setTitle(prev => prev === "Fretux" ? "Frederik Spirgi" : "Fretux");
|
||||||
setPhase("fadeIn");
|
setPhase("fadeIn");
|
||||||
setTimeout(() => {
|
|
||||||
setPhase("normal");
|
fadeTimeout = setTimeout(() => setPhase("normal"), 500);
|
||||||
}, 500);
|
|
||||||
}, 500);
|
}, 500);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
return () => clearInterval(interval);
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
clearTimeout(fadeTimeout);
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
@@ -62,7 +66,8 @@ export default function Home() {
|
|||||||
<section className="section">
|
<section className="section">
|
||||||
<div className="textLeft">
|
<div className="textLeft">
|
||||||
<p>
|
<p>
|
||||||
I'm a passionate developer exploring web, game, and backend technologies with a focus on innovation and creativity.
|
I'm a passionate developer exploring web, game, and backend technologies with a focus on
|
||||||
|
innovation and creativity.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="imageRight">
|
<div className="imageRight">
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
const projectData = [
|
||||||
|
{
|
||||||
|
title: "Red Lake Stats",
|
||||||
|
description: "An interactive Javascript and Python application designed to calculate damage statistics for the Roblox game 'The Red Lake'",
|
||||||
|
image: "/images/portfolio-project1.png",
|
||||||
|
link: "https://fretux.ch/trlstats",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "SBB-History",
|
||||||
|
description: "A website about the creation of the SBB (Swiss Train Corporation) with an interactable map!",
|
||||||
|
image: "/images/portfolio-project2.png",
|
||||||
|
link: "https://sbb-history.fretux.ch",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Fretux.ch",
|
||||||
|
description: "My first portfolio website, gameified for more user interaction.",
|
||||||
|
image: "/images/portfolio-project3.png",
|
||||||
|
link: "https://fretux.ch",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function ProjectsPage() {
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
const [fade, setFade] = useState(false);
|
||||||
|
|
||||||
|
const handleNavigation = (direction) => {
|
||||||
|
setFade(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setCurrentIndex((prev) => {
|
||||||
|
const newIndex =
|
||||||
|
direction === "next"
|
||||||
|
? (prev + 1) % projectData.length
|
||||||
|
: (prev - 1 + projectData.length) % projectData.length;
|
||||||
|
return newIndex;
|
||||||
|
});
|
||||||
|
setFade(false);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
const project = projectData[currentIndex];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="projectContainer">
|
||||||
|
<div className={`projectCard ${fade ? "fade-out" : "fade-in"}`}>
|
||||||
|
<h2 className="projectTitle">{project.title}</h2>
|
||||||
|
<Image
|
||||||
|
src={project.image}
|
||||||
|
alt={project.title}
|
||||||
|
width={600}
|
||||||
|
height={400}
|
||||||
|
className="projectImage"
|
||||||
|
/>
|
||||||
|
<p className="projectDescription">{project.description}</p>
|
||||||
|
<a href={project.link} target="_blank" rel="noopener noreferrer">
|
||||||
|
<button className="learnMoreButton" style={{ marginTop: "1.5rem" }}>
|
||||||
|
View Project
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="projectNavigation">
|
||||||
|
<button onClick={() => handleNavigation("prev")} className="arrowButton">
|
||||||
|
←
|
||||||
|
</button>
|
||||||
|
<button onClick={() => handleNavigation("next")} className="arrowButton">
|
||||||
|
→
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user