This commit is contained in:
parent
f45ca70b21
commit
03711da9ef
15
package-lock.json
generated
15
package-lock.json
generated
@ -11,6 +11,7 @@
|
|||||||
"hamburger-react": "^2.5.0",
|
"hamburger-react": "^2.5.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-icons": "^4.12.0",
|
||||||
"react-image-gallery": "^1.3.0",
|
"react-image-gallery": "^1.3.0",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scroll-motion": "^0.3.0",
|
"react-scroll-motion": "^0.3.0",
|
||||||
@ -1984,6 +1985,14 @@
|
|||||||
"react": "^18.2.0"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-icons": {
|
||||||
|
"version": "4.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
|
||||||
|
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-image-gallery": {
|
"node_modules/react-image-gallery": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-image-gallery/-/react-image-gallery-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-image-gallery/-/react-image-gallery-1.3.0.tgz",
|
||||||
@ -3713,6 +3722,12 @@
|
|||||||
"scheduler": "^0.23.0"
|
"scheduler": "^0.23.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-icons": {
|
||||||
|
"version": "4.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
|
||||||
|
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"react-image-gallery": {
|
"react-image-gallery": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-image-gallery/-/react-image-gallery-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-image-gallery/-/react-image-gallery-1.3.0.tgz",
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
"hamburger-react": "^2.5.0",
|
"hamburger-react": "^2.5.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-icons": "^4.12.0",
|
||||||
"react-image-gallery": "^1.3.0",
|
"react-image-gallery": "^1.3.0",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scroll-motion": "^0.3.0",
|
"react-scroll-motion": "^0.3.0",
|
||||||
|
|||||||
@ -6,7 +6,9 @@ import Contact from "./pages/Contact";
|
|||||||
import Footer from "./components/Footer";
|
import Footer from "./components/Footer";
|
||||||
import Header from "./components/Header";
|
import Header from "./components/Header";
|
||||||
import ExperianceDetail from "./pages/ExperienceDetail";
|
import ExperianceDetail from "./pages/ExperienceDetail";
|
||||||
|
import FullPage from "./pages/FullPage";
|
||||||
import { RecoilRoot } from "recoil";
|
import { RecoilRoot } from "recoil";
|
||||||
|
import ScrollToAnchor from "./components/ScrollToAnchor";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
@ -14,10 +16,11 @@ function App() {
|
|||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
<main className=" min-h-screen">
|
<main className=" min-h-screen">
|
||||||
<Header />
|
<Header />
|
||||||
|
<ScrollToAnchor />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<FullPage />} />
|
||||||
<Route path="/experience" element={<Experience />} />
|
{/* <Route path="/experience" element={<Experience />} />
|
||||||
<Route path="/contact" element={<Contact />} />
|
<Route path="/contact" element={<Contact />} />*/}
|
||||||
<Route path="/experience/:id" element={<ExperianceDetail />} />
|
<Route path="/experience/:id" element={<ExperianceDetail />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@ -1,16 +1,21 @@
|
|||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
import { Turn as Hamburger } from "hamburger-react";
|
import { useState, useEffect } from "react";
|
||||||
import { useState } from "react";
|
import { Divide as Hamburger } from "hamburger-react";
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
const [isOpen, setOpen] = useState(false);
|
const [isOpen, setOpen] = useState(false);
|
||||||
|
|
||||||
const menuTimeout = 400;
|
const menuTimeout = 400;
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.style.overflow = isOpen ? "hidden" : "unset";
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
const menu = [
|
const menu = [
|
||||||
{ link: "/", title: ".me()" },
|
{ link: "/#about", title: ".me()" },
|
||||||
{ link: "/experience", title: ".experience()" },
|
{ link: "/#experience", title: ".experience()" },
|
||||||
{ link: "/contact", title: ".contact()" },
|
{ link: "/#contact", title: ".contact()" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const menuUI = menu.map((item) => {
|
const menuUI = menu.map((item) => {
|
||||||
@ -21,38 +26,70 @@ function Header() {
|
|||||||
className += " text-white/40";
|
className += " text-white/40";
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<li key={item.link}>
|
<li className="my-10 text-xl md:my-0 md:text-base" key={item.link}>
|
||||||
<Link className={className} to={item.link}>
|
<Link
|
||||||
|
className={className}
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
to={item.link}
|
||||||
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const headerClasses = ["sticky", "top-0", "z-40", "backdrop-blur-sm", "h-16"];
|
||||||
|
const logoClasses = ["hover:drop-shadow-light"];
|
||||||
|
const overlayMenu = [
|
||||||
|
"bg-black/90",
|
||||||
|
"z-50",
|
||||||
|
"fixed",
|
||||||
|
"left-0",
|
||||||
|
"right-0",
|
||||||
|
"top-16",
|
||||||
|
"h-screen",
|
||||||
|
"backdrop-blur-sm",
|
||||||
|
"p-2",
|
||||||
|
];
|
||||||
|
if (isOpen) {
|
||||||
|
headerClasses.push("bg-black/90");
|
||||||
|
logoClasses.push("drop-shadow-yellow");
|
||||||
|
} else {
|
||||||
|
headerClasses.push("bg-bgColor/90");
|
||||||
|
logoClasses.push("drop-shadow-doublelight");
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-50 backdrop-blur-sm bg-bgColor/90 ">
|
<>
|
||||||
<div className="container mx-auto">
|
{isOpen && (
|
||||||
<nav className="flex items-center mx-4 py-4">
|
<div className={overlayMenu.join(" ")}>
|
||||||
<div className="flex-none text-4xl font-black">
|
<div className=" h-[calc(100vh-20rem)] flex flex-col justify-center">
|
||||||
<Link
|
<ul>{menuUI}</ul>
|
||||||
className=" drop-shadow-doublelight hover:drop-shadow-light"
|
</div>
|
||||||
to="/"
|
</div>
|
||||||
>
|
)}
|
||||||
|
<header className={headerClasses.join(" ")}>
|
||||||
|
<div className="container mx-auto h-full">
|
||||||
|
<nav className="flex items-center h-full px-2">
|
||||||
|
<div className="flex-none text-4xl font-black ">
|
||||||
|
<Link className={logoClasses.join(" ")} to="/#start">
|
||||||
MS.
|
MS.
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="hamburger">
|
|
||||||
<Hamburger color="#e5e5ff" toggled={isOpen} toggle={setOpen} />
|
|
||||||
</div> */}
|
|
||||||
<div className="grow"></div>
|
<div className="grow"></div>
|
||||||
<div className="flex-none ">
|
<div className="flex-none hidden md:block ">
|
||||||
<ul className="flex flex-row gap-4 text-lg">{menuUI}</ul>
|
<ul className="flex flex-row gap-4 text-lg">{menuUI}</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-none block md:hidden">
|
||||||
|
<Hamburger toggled={isOpen} toggle={setOpen} duration={0.9} />
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{isOpen && hamburgerMenu}
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
src/components/ScrollToAnchor.jsx
Normal file
28
src/components/ScrollToAnchor.jsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
|
||||||
|
function ScrollToAnchor() {
|
||||||
|
const location = useLocation();
|
||||||
|
const lastHash = useRef("");
|
||||||
|
|
||||||
|
// listen to location change using useEffect with location as dependency
|
||||||
|
// https://jasonwatmore.com/react-router-v6-listen-to-location-route-change-without-history-listen
|
||||||
|
useEffect(() => {
|
||||||
|
if (location.hash) {
|
||||||
|
lastHash.current = location.hash.slice(1); // safe hash for further use after navigation
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastHash.current && document.getElementById(lastHash.current)) {
|
||||||
|
setTimeout(() => {
|
||||||
|
document
|
||||||
|
.getElementById(lastHash.current)
|
||||||
|
?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||||
|
lastHash.current = "";
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ScrollToAnchor;
|
||||||
@ -1,12 +1,12 @@
|
|||||||
function Tags({ listOfTags }) {
|
function Tags({ listOfTags }) {
|
||||||
const tagList = listOfTags.map((itemTag, keyTag) => {
|
const tagList = listOfTags.map((itemTag, keyTag) => {
|
||||||
return (
|
return (
|
||||||
<div className={`bg-indigo-500/40 py-2 px-4 rounded-full `} key={keyTag}>
|
<div className={`bg-gray-600 py-1 px-1 rounded-xl `} key={keyTag}>
|
||||||
{itemTag}
|
{itemTag}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return <div className="text-xs flex gap-4 mt-6 ">{tagList}</div>;
|
return <div className="text-xs flex gap-2 mt-6 ">{tagList}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Tags;
|
export default Tags;
|
||||||
|
|||||||
@ -4,5 +4,5 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
body {
|
body {
|
||||||
background-color: #302f39;
|
background-color: #031417;
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/pages/About.jsx
Normal file
10
src/pages/About.jsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
function About() {
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<div id="about" className=" absolute -top-16 "></div>
|
||||||
|
<h1> About</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default About;
|
||||||
@ -1,7 +1,8 @@
|
|||||||
function Contact() {
|
function Contact() {
|
||||||
return (
|
return (
|
||||||
<div className="container content">
|
<div className="relative">
|
||||||
<h1>Welcome to Contact</h1>
|
<div id="contact" className=" absolute -top-16 "></div>
|
||||||
|
<h1>Welcome to C#ontact</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,8 +49,9 @@ function Experiance() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto my-10 px-6">
|
<div className="relative">
|
||||||
<h1>Welcome to Experiance</h1>
|
<div id="experience" className=" absolute -top-16 "></div>
|
||||||
|
<h1>Welcome to Experience</h1>
|
||||||
<div className="py-4">{experianceListUI}</div>
|
<div className="py-4">{experianceListUI}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
import { useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { useRecoilValue } from "recoil";
|
import { useRecoilValue } from "recoil";
|
||||||
import { projectsAtom } from "../store";
|
import { projectsAtom } from "../store";
|
||||||
import ImageGallery from "react-image-gallery";
|
import ImageGallery from "react-image-gallery";
|
||||||
import Tags from "../components/Tags";
|
import Tags from "../components/Tags";
|
||||||
|
import { IoChevronBackOutline as BackButton } from "react-icons/io5";
|
||||||
|
|
||||||
function ExperianceDetail() {
|
function ExperianceDetail() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const experianceList = useRecoilValue(projectsAtom);
|
const experianceList = useRecoilValue(projectsAtom);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
//shorter variant of Find function with IF-sats
|
//shorter variant of Find function with IF-sats
|
||||||
const myProject = experianceList.find((item) => item.id === id);
|
const myProject = experianceList.find((item) => item.id === id);
|
||||||
@ -35,6 +37,15 @@ function ExperianceDetail() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto my-10 px-6">
|
<div className="container mx-auto my-10 px-6">
|
||||||
|
<button
|
||||||
|
className="text-4xl"
|
||||||
|
aria-label="Back"
|
||||||
|
onClick={() => {
|
||||||
|
navigate(-1);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BackButton />
|
||||||
|
</button>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h1>Project: {myProject.title}</h1>
|
<h1>Project: {myProject.title}</h1>
|
||||||
@ -43,8 +54,8 @@ function ExperianceDetail() {
|
|||||||
<Tags listOfTags={myProject.tags} />
|
<Tags listOfTags={myProject.tags} />
|
||||||
</div>
|
</div>
|
||||||
{linkUI}
|
{linkUI}
|
||||||
<div className="py-4 mb-8">{myProject.info}</div>
|
<div className="flex flex-col md:flex-row gap-4">
|
||||||
<div className="">
|
<div className="flex-1">
|
||||||
<ImageGallery
|
<ImageGallery
|
||||||
showThumbnails={false}
|
showThumbnails={false}
|
||||||
showBullets={true}
|
showBullets={true}
|
||||||
@ -54,8 +65,11 @@ function ExperianceDetail() {
|
|||||||
items={projectImg}
|
items={projectImg}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-1">{myProject.info}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
4;
|
||||||
|
|
||||||
export default ExperianceDetail;
|
export default ExperianceDetail;
|
||||||
|
|||||||
17
src/pages/FullPage.jsx
Normal file
17
src/pages/FullPage.jsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import About from "./About";
|
||||||
|
import Contact from "./Contact";
|
||||||
|
import Experiance from "./Experience";
|
||||||
|
import Start from "./Start";
|
||||||
|
|
||||||
|
function FullPage() {
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto px-2">
|
||||||
|
<Start />
|
||||||
|
<About />
|
||||||
|
<Experiance />
|
||||||
|
<Contact />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FullPage;
|
||||||
18
src/pages/Start.jsx
Normal file
18
src/pages/Start.jsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
function Start() {
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<div id="start" className="absolute -top-16 "></div>
|
||||||
|
<div>
|
||||||
|
<h1> Start</h1>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eos nostrum
|
||||||
|
repudiandae, excepturi, eaque autem tenetur commodi qui praesentium
|
||||||
|
nesciunt atque ullam consectetur cum aliquam corporis quae maxime libero
|
||||||
|
impedit exercitationem?
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Start;
|
||||||
@ -4,7 +4,7 @@ const experianceList = [
|
|||||||
{
|
{
|
||||||
id: "46bf76ae-8915-4e5d-ae92-4151be80e75a",
|
id: "46bf76ae-8915-4e5d-ae92-4151be80e75a",
|
||||||
title: "Netzero web",
|
title: "Netzero web",
|
||||||
info: "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Beatae cumque laborum, placeat nobis fugit nemo ipsa voluptates error quo possimus ea velit quos voluptatum magnam id eius quam accusamus. Eum blanditiis aperiam minus inventore laboriosam, et vel ipsam perspiciatis a facilis cum, iure alias recusandae dolorem adipisci illum. Quo maxime nisi minus mollitia praesentium cumque, temporibus incidunt nulla culpa eligendi consequatur doloremque repudiandae aspernatur quas necessitatibus tenetur. Similique fuga rerum provident distinctio doloremque qui accusamus, sequi voluptate eveniet voluptatum autem odio placeat quasi temporibus quas nulla laborum sunt tenetur dolorum, incidunt error porro amet modi? Temporibus amet optio mollitia omnis?",
|
info: "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Beatae cumque laborum, placeat nobis fugit nemo ipsa voluptates error quo possimus ea velit quos voluptatum magnam id eius quam accusamus. Eum blanditiis aperiam minus inventore laboriosam, et vel ipsam perspiciatis a facilis cum, iure alias recusandae dolorem adipisci illum. Quo maxime nisi minus mollitia praesentium cumque, temporibus incidunt nulla culpa eligendi consequatur doloremque repudiandae aspernatur quas necessitatibus tenetur. ",
|
||||||
img: [
|
img: [
|
||||||
"/img/placeholder.png",
|
"/img/placeholder.png",
|
||||||
"/img/placeholder.png",
|
"/img/placeholder.png",
|
||||||
@ -17,7 +17,7 @@ const experianceList = [
|
|||||||
{
|
{
|
||||||
id: "55515a25-deb1-451c-bc7d-006d293f54aa",
|
id: "55515a25-deb1-451c-bc7d-006d293f54aa",
|
||||||
title: "Lets fly",
|
title: "Lets fly",
|
||||||
info: "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Beatae cumque laborum, placeat nobis fugit nemo ipsa voluptates error quo possimus ea velit quos voluptatum magnam id eius quam accusamus. Eum blanditiis aperiam minus inventore laboriosam, et vel ipsam perspiciatis a facilis cum, iure alias recusandae dolorem adipisci illum. Quo maxime nisi minus mollitia praesentium cumque, temporibus incidunt nulla culpa eligendi consequatur doloremque repudiandae aspernatur quas necessitatibus tenetur. Similique fuga rerum provident distinctio doloremque qui accusamus, sequi voluptate eveniet voluptatum autem odio placeat quasi temporibus quas nulla laborum sunt tenetur dolorum, incidunt error porro amet modi? Temporibus amet optio mollitia omnis?",
|
info: "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Beatae cumque laborum, placeat nobis fugit nemo ipsa voluptates error quo possimus ea velit quos voluptatum magnam id eius quam accusamus. Eum blanditiis aperiam minus inventore laboriosam, et vel ipsam perspiciatis a facilis cum, iure alias recusandae dolorem adipisci illum. Quo maxime nisi minus mollitia praesentium cumque, temporibus incidunt nulla culpa eligendi consequatur doloremque repudiandae aspernatur quas necessitatibus tenetur. ",
|
||||||
img: [
|
img: [
|
||||||
"/img/placeholder.png",
|
"/img/placeholder.png",
|
||||||
"/img/placeholder.png",
|
"/img/placeholder.png",
|
||||||
|
|||||||
@ -13,6 +13,7 @@ export default {
|
|||||||
},
|
},
|
||||||
dropShadow: {
|
dropShadow: {
|
||||||
light: "0 0 5px theme('colors.indigo.800')",
|
light: "0 0 5px theme('colors.indigo.800')",
|
||||||
|
yellow: "0 0 9px theme('colors.lime.400')",
|
||||||
doublelight: [
|
doublelight: [
|
||||||
"0 0 5px theme('colors.lime.400')",
|
"0 0 5px theme('colors.lime.400')",
|
||||||
"0 0 15px theme('colors.yellow.400')",
|
"0 0 15px theme('colors.yellow.400')",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user