Compare commits
10 Commits
67de731eab
...
90398455f1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90398455f1 | ||
|
|
90da024c00 | ||
|
|
a2d35650c6 | ||
|
|
f237dff5c7 | ||
|
|
279b5ad3d0 | ||
|
|
f538f7b844 | ||
|
|
deb67c4a68 | ||
|
|
b3e699f4b1 | ||
|
|
c4e8900e24 | ||
| 37eb8de494 |
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
.git
|
||||||
|
.envrc
|
||||||
|
.gitignore
|
||||||
35
.gitlab-ci.yml
Normal file
35
.gitlab-ci.yml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
variables:
|
||||||
|
TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
|
||||||
|
TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA
|
||||||
|
|
||||||
|
build:
|
||||||
|
image: docker:latest
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- deployment
|
||||||
|
script:
|
||||||
|
- echo "Building"
|
||||||
|
- export
|
||||||
|
- docker build -t $TAG_COMMIT -t $TAG_LATEST .
|
||||||
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
|
- docker push $TAG_COMMIT
|
||||||
|
- docker push $TAG_LATEST
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
image: docker:latest
|
||||||
|
stage: deploy
|
||||||
|
tags:
|
||||||
|
- deployment
|
||||||
|
script:
|
||||||
|
- echo "Deploying"
|
||||||
|
- chmod og= $ID_RSA
|
||||||
|
- apk update && apk add openssh-client
|
||||||
|
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY"
|
||||||
|
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $TAG_COMMIT"
|
||||||
|
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f $DOCKER_NAME || true"
|
||||||
|
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d --network=$DOCKER_NETWORK --restart unless-stopped --name $DOCKER_NAME $TAG_COMMIT"
|
||||||
|
- ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "/usr/local/bin/caddycontrol -host $CADDYCONTROL_HOST -dial $CADDYCONTROL_DIAL"
|
||||||
5
Caddyfile
Normal file
5
Caddyfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
:80 {
|
||||||
|
root * /usr/share/caddy
|
||||||
|
try_files {path} /index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM node:17.1.0-alpine3.12 as builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json ./
|
||||||
|
COPY package-lock.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY ./ ./
|
||||||
|
RUN NODE_ENV=production npm run build
|
||||||
|
|
||||||
|
|
||||||
|
FROM caddy:2-alpine
|
||||||
|
WORKDIR /usr/share/caddy
|
||||||
|
COPY Caddyfile /etc/caddy/Caddyfile
|
||||||
|
COPY --from=builder ./app/dist .
|
||||||
|
|
||||||
15
index.html
15
index.html
@ -2,8 +2,21 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link
|
||||||
|
rel="icon"
|
||||||
|
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22>
|
||||||
|
<text y=%22.9em%22 font-size=%2290%22>
|
||||||
|
👋
|
||||||
|
</text>
|
||||||
|
</svg>"
|
||||||
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
<title>Mariia Shabelnik</title>
|
<title>Mariia Shabelnik</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
2154
package-lock.json
generated
2154
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -4,19 +4,26 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite --host",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"hamburger-react": "^2.5.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^6.3.0"
|
"react-image-gallery": "^1.3.0",
|
||||||
|
"react-router-dom": "^6.3.0",
|
||||||
|
"react-scroll-motion": "^0.3.0",
|
||||||
|
"recoil": "^0.7.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@vitejs/plugin-react": "^2.0.0",
|
"@vitejs/plugin-react": "^2.0.0",
|
||||||
|
"autoprefixer": "^10.4.15",
|
||||||
|
"postcss": "^8.4.29",
|
||||||
|
"tailwindcss": "^3.3.3",
|
||||||
"vite": "^3.0.0"
|
"vite": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
BIN
public/img/placeholder.png
Normal file
BIN
public/img/placeholder.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
90
src/App.css
90
src/App.css
@ -1,12 +1,46 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Roboto Mono", monospace;
|
||||||
|
background-color: #302f39;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
border: 2px solid red;
|
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
padding: 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav .container {
|
||||||
|
height: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-top: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
background-color: rgb(84, 84, 84);
|
background-color: #302f38;
|
||||||
height: 3em;
|
height: 4em;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*box-shadow: inset 0px 3px 20px 10px rgba(0, 0, 0, 0.3);*/
|
||||||
|
|
||||||
|
.nav a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #e5e5ff;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav a:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 0 5px #f2ef00;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-items {
|
.nav-items {
|
||||||
@ -21,5 +55,55 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.menu-items div {
|
.menu-items div {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo a {
|
||||||
|
text-shadow: 0 0 5px #ccff00, 0 0 15px #ccff00;
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
font-size: 0.7em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-menu {
|
||||||
|
background-color: #302f38;
|
||||||
|
z-index: 100;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
backdrop-filter: blur(3px) contrast(60%);
|
||||||
|
-webkit-backdrop-filter: blur(3px) contrast(60%);
|
||||||
|
top: 4em;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-menu a {
|
||||||
|
font-size: 2em;
|
||||||
|
text-decoration: none;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.hamburger {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.menu-items {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
19
src/App.jsx
19
src/App.jsx
@ -1,21 +1,28 @@
|
|||||||
import "./App.css";
|
//import "./App.css";
|
||||||
import { Routes, Route, Link } from "react-router-dom";
|
import { Routes, Route } from "react-router-dom";
|
||||||
import Home from "./pages/Home";
|
import Home from "./pages/Home";
|
||||||
import Experiance from "./pages/Experiance";
|
import Experience from "./pages/Experience";
|
||||||
import Contact from "./pages/Contact";
|
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 { RecoilRoot } from "recoil";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="text-white">
|
||||||
|
<RecoilRoot>
|
||||||
|
<main className=" min-h-screen">
|
||||||
<Header />
|
<Header />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="experiance" element={<Experiance />} />
|
<Route path="/experience" element={<Experience />} />
|
||||||
<Route path="contact" element={<Contact />} />
|
<Route path="/contact" element={<Contact />} />
|
||||||
|
<Route path="/experience/:id" element={<ExperianceDetail />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
</main>
|
||||||
|
</RecoilRoot>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
function Footer() {
|
function Footer() {
|
||||||
return <div className="container">Footer</div>;
|
const fullYear = new Date().getFullYear();
|
||||||
|
return (
|
||||||
|
<footer className="container mx-auto my-10 px-6 sticky top-[95vh]">
|
||||||
|
<div className=" text-center text-sm text-white/50 ">
|
||||||
|
© {fullYear} Mariia Shabelnik, all rights reserved
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Footer;
|
export default Footer;
|
||||||
|
|||||||
@ -1,25 +1,58 @@
|
|||||||
import { Routes, Route, Link } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
|
import { Turn as Hamburger } from "hamburger-react";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
|
const [isOpen, setOpen] = useState(false);
|
||||||
|
const menuTimeout = 400;
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
const menu = [
|
||||||
|
{ link: "/", title: ".me()" },
|
||||||
|
{ link: "/experience", title: ".experience()" },
|
||||||
|
{ link: "/contact", title: ".contact()" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const menuUI = menu.map((item) => {
|
||||||
|
let className = "drop-shadow-light hover:drop-shadow-doublelight";
|
||||||
|
if (location.pathname === item.link) {
|
||||||
|
className += " text-white";
|
||||||
|
} else {
|
||||||
|
className += " text-white/40";
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="nav">
|
<li key={item.link}>
|
||||||
<div className="container nav-items">
|
<Link className={className} to={item.link}>
|
||||||
<div className="logo">
|
{item.title}
|
||||||
<Link to="/">LOGO</Link>
|
</Link>
|
||||||
</div>
|
</li>
|
||||||
<div className="menu-items">
|
);
|
||||||
<div>
|
});
|
||||||
<Link to="/">About</Link>
|
|
||||||
</div>
|
return (
|
||||||
<div>
|
<header className="sticky top-0 z-50 backdrop-blur-sm bg-bgColor/90 ">
|
||||||
<Link to="/experiance">Experiance</Link>
|
<div className="container mx-auto">
|
||||||
</div>
|
<nav className="flex items-center mx-4 py-4">
|
||||||
<div>
|
<div className="flex-none text-4xl font-black">
|
||||||
<Link to="/contact">Contact</Link>
|
<Link
|
||||||
</div>
|
className=" drop-shadow-doublelight hover:drop-shadow-light"
|
||||||
|
to="/"
|
||||||
|
>
|
||||||
|
MS.
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
{/* <div className="hamburger">
|
||||||
|
<Hamburger color="#e5e5ff" toggled={isOpen} toggle={setOpen} />
|
||||||
|
</div> */}
|
||||||
|
<div className="grow"></div>
|
||||||
|
<div className="flex-none ">
|
||||||
|
<ul className="flex flex-row gap-4 text-lg">{menuUI}</ul>
|
||||||
</div>
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{isOpen && hamburgerMenu}
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
src/components/Tags.jsx
Normal file
12
src/components/Tags.jsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
function Tags({ listOfTags }) {
|
||||||
|
const tagList = listOfTags.map((itemTag, keyTag) => {
|
||||||
|
return (
|
||||||
|
<div className={`bg-indigo-500/40 py-2 px-4 rounded-full `} key={keyTag}>
|
||||||
|
{itemTag}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return <div className="text-xs flex gap-4 mt-6 ">{tagList}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tags;
|
||||||
@ -1,3 +1,8 @@
|
|||||||
|
@import "react-image-gallery/styles/css/image-gallery.css";
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
background-color: #302f39;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
function Contact() {
|
function Contact() {
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container content">
|
||||||
<h1>Welcome to Contact</h1>
|
<h1>Welcome to Contact</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
function Experiance() {
|
|
||||||
return (
|
|
||||||
<div className="container">
|
|
||||||
<h1>Welcome to Experiance</h1>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Experiance;
|
|
||||||
59
src/pages/Experience.jsx
Normal file
59
src/pages/Experience.jsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { useRecoilValue } from "recoil";
|
||||||
|
import { projectsAtom } from "../store";
|
||||||
|
import Tags from "../components/Tags";
|
||||||
|
|
||||||
|
function Experiance() {
|
||||||
|
const experianceList = useRecoilValue(projectsAtom);
|
||||||
|
|
||||||
|
const experianceListUI = experianceList.map((item, key) => {
|
||||||
|
const position = key % 2;
|
||||||
|
|
||||||
|
const imgClasses = ["flex-1", "hidden", "md:block"];
|
||||||
|
|
||||||
|
if (position === 1) {
|
||||||
|
imgClasses.push("md:order-last");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="flex flex-col md:flex-row gap-4 mb-12" key={item.id}>
|
||||||
|
<div className={imgClasses.join(" ")}>
|
||||||
|
<img className="rounded-md" src={item.img[0]} />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 flex flex-col">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-2xl mb-4"> {item.title}</h2>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
className="block md:hidden mb-4 rounded-md"
|
||||||
|
src={item.img[0]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm">
|
||||||
|
<p>{item.info}</p>
|
||||||
|
</div>
|
||||||
|
<Tags listOfTags={item.tags} />
|
||||||
|
<div className="grow"></div>
|
||||||
|
<div className=" text-right">
|
||||||
|
<Link
|
||||||
|
className=" drop-shadow-doublelight hover:drop-shadow-light "
|
||||||
|
to={`/experience/${item.id}`}
|
||||||
|
>
|
||||||
|
read more
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto my-10 px-6">
|
||||||
|
<h1>Welcome to Experiance</h1>
|
||||||
|
<div className="py-4">{experianceListUI}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Experiance;
|
||||||
61
src/pages/ExperienceDetail.jsx
Normal file
61
src/pages/ExperienceDetail.jsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { useRecoilValue } from "recoil";
|
||||||
|
import { projectsAtom } from "../store";
|
||||||
|
import ImageGallery from "react-image-gallery";
|
||||||
|
import Tags from "../components/Tags";
|
||||||
|
|
||||||
|
function ExperianceDetail() {
|
||||||
|
const { id } = useParams();
|
||||||
|
const experianceList = useRecoilValue(projectsAtom);
|
||||||
|
|
||||||
|
//shorter variant of Find function with IF-sats
|
||||||
|
const myProject = experianceList.find((item) => item.id === id);
|
||||||
|
|
||||||
|
if (myProject === undefined) {
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto my-10 px-6">
|
||||||
|
404 the project does not exists
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectImg = myProject.img.map((item) => {
|
||||||
|
return { original: item, thumbnail: item };
|
||||||
|
});
|
||||||
|
|
||||||
|
let linkUI = <></>;
|
||||||
|
|
||||||
|
if (myProject.link !== undefined) {
|
||||||
|
linkUI = (
|
||||||
|
<a href={myProject.link} target="_blank">
|
||||||
|
Visit page
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto my-10 px-6">
|
||||||
|
<div className="flex">
|
||||||
|
<div className="flex-1">
|
||||||
|
<h1>Project: {myProject.title}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tags listOfTags={myProject.tags} />
|
||||||
|
</div>
|
||||||
|
{linkUI}
|
||||||
|
<div className="py-4 mb-8">{myProject.info}</div>
|
||||||
|
<div className="">
|
||||||
|
<ImageGallery
|
||||||
|
showThumbnails={false}
|
||||||
|
showBullets={true}
|
||||||
|
autoPlay={true}
|
||||||
|
slideDuration={1000}
|
||||||
|
slideInterval={4000}
|
||||||
|
items={projectImg}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExperianceDetail;
|
||||||
@ -1,8 +1,77 @@
|
|||||||
|
import {
|
||||||
|
Animator,
|
||||||
|
ScrollContainer,
|
||||||
|
ScrollPage,
|
||||||
|
batch,
|
||||||
|
Fade,
|
||||||
|
FadeIn,
|
||||||
|
FadeOut,
|
||||||
|
Move,
|
||||||
|
MoveIn,
|
||||||
|
MoveOut,
|
||||||
|
Sticky,
|
||||||
|
StickyIn,
|
||||||
|
StickyOut,
|
||||||
|
Zoom,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut,
|
||||||
|
} from "react-scroll-motion";
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
|
const ZoomInScrollOut = batch(StickyIn(), FadeIn(), ZoomIn());
|
||||||
|
const FadeUp = batch(Fade(), Move(), Sticky());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<ScrollContainer>
|
||||||
<h1>Welcome to Home + About me</h1>
|
<ScrollPage>
|
||||||
|
<Animator animation={batch(Fade(), Sticky(), MoveOut(0, 200))}>
|
||||||
|
<span>Hello, my name is Mariia 😀</span>
|
||||||
|
</Animator>
|
||||||
|
<span style={{ fontSize: "40px" }}>
|
||||||
|
<Animator animation={MoveIn(-1000, 0)}>Hello Guys 👋🏻</Animator>
|
||||||
|
</span>
|
||||||
|
</ScrollPage>
|
||||||
|
|
||||||
|
<ScrollPage>
|
||||||
|
<Animator animation={ZoomInScrollOut}>
|
||||||
|
<span style={{ fontSize: "40px" }}>I'm Frontend developer ✨</span>
|
||||||
|
</Animator>
|
||||||
|
</ScrollPage>
|
||||||
|
|
||||||
|
<ScrollPage>
|
||||||
|
<Animator animation={FadeUp}>
|
||||||
|
<span style={{ fontSize: "40px" }}>I'm Webbdesigner ⛅️</span>
|
||||||
|
</Animator>
|
||||||
|
</ScrollPage>
|
||||||
|
|
||||||
|
<ScrollPage>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ fontSize: "40px" }}>
|
||||||
|
<Animator animation={MoveIn(1000, 0)}>Nice to meet you 🙋🏻♀️</Animator>
|
||||||
|
- I'm Dante Chun -
|
||||||
|
<Animator animation={MoveOut(1000, 0)}>Good bye ✋🏻</Animator>
|
||||||
|
<Animator animation={MoveOut(-1000, 0)}>See you 💛</Animator>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</ScrollPage>
|
||||||
|
|
||||||
|
<ScrollPage>
|
||||||
|
<Animator animation={batch(Fade(), Sticky())}>
|
||||||
|
<span style={{ fontSize: "40px" }}>Done</span>
|
||||||
|
<br />
|
||||||
|
<span style={{ fontSize: "30px" }}>
|
||||||
|
There's FadeAnimation, MoveAnimation, StickyAnimation, ZoomAnimation
|
||||||
|
</span>
|
||||||
|
</Animator>
|
||||||
|
</ScrollPage>
|
||||||
|
</ScrollContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
71
src/store.js
Normal file
71
src/store.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { atom } from "recoil";
|
||||||
|
|
||||||
|
const experianceList = [
|
||||||
|
{
|
||||||
|
id: "46bf76ae-8915-4e5d-ae92-4151be80e75a",
|
||||||
|
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?",
|
||||||
|
img: [
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
],
|
||||||
|
tags: ["react", "vite", "wordpress"],
|
||||||
|
link: "https://www.net0.se",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "55515a25-deb1-451c-bc7d-006d293f54aa",
|
||||||
|
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?",
|
||||||
|
img: [
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
],
|
||||||
|
tags: ["react", "vite", "shopify"],
|
||||||
|
link: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "e93a5d54-3442-4b19-b568-8ae550aa09fe",
|
||||||
|
title: "Project 3",
|
||||||
|
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?",
|
||||||
|
img: [
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
],
|
||||||
|
tags: ["react", "vite", "wordpress"],
|
||||||
|
link: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "cedeb531-0409-4e1f-b7e9-9668dcaa5e71",
|
||||||
|
title: "Project 4",
|
||||||
|
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?",
|
||||||
|
img: [
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
],
|
||||||
|
tags: ["react", "vite", "wordpress"],
|
||||||
|
link: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "5e2ea8b8-bb1e-4c9d-a723-42406bf7be72",
|
||||||
|
title: "Project 5",
|
||||||
|
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?",
|
||||||
|
img: [
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
"/img/placeholder.png",
|
||||||
|
],
|
||||||
|
tags: ["react", "vite", "wordpress"],
|
||||||
|
link: undefined,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const projectsAtom = atom({ key: "projects", default: experianceList });
|
||||||
28
tailwind.config.js
Normal file
28
tailwind.config.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||||
|
theme: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ["Roboto Mono", "system-ui"],
|
||||||
|
headline: ["Roboto Mono", "system-ui"],
|
||||||
|
},
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
neon: "#ccff00",
|
||||||
|
bgColor: "#302f39",
|
||||||
|
},
|
||||||
|
dropShadow: {
|
||||||
|
light: "0 0 5px theme('colors.indigo.800')",
|
||||||
|
doublelight: [
|
||||||
|
"0 0 5px theme('colors.lime.400')",
|
||||||
|
"0 0 15px theme('colors.yellow.400')",
|
||||||
|
],
|
||||||
|
active: [
|
||||||
|
"0 0 5px theme('colors.lime.400')",
|
||||||
|
"0 0 15px theme('colors.indigo.950')",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
};
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from "vite";
|
||||||
import react from '@vitejs/plugin-react'
|
import react from "@vitejs/plugin-react";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()]
|
plugins: [react()],
|
||||||
})
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user