Compare commits

..

28 Commits

Author SHA1 Message Date
d791e4ffcc Update apge
All checks were successful
ci/cd / Build (push) Successful in 7s
2025-05-05 21:21:55 +02:00
fe38d6af18 Added animation
All checks were successful
ci/cd / Build (push) Successful in 10s
2025-05-05 21:12:34 +02:00
09cc4cb09b added more tags
All checks were successful
ci/cd / Build (push) Successful in 6s
2025-05-05 21:06:20 +02:00
660f59530a added it support
All checks were successful
ci/cd / Build (push) Successful in 7s
2025-05-05 21:03:22 +02:00
8e241cc6e9 fix contacty
All checks were successful
ci/cd / Build (push) Successful in 6s
2025-05-05 20:57:53 +02:00
11a432a2c1 Update info
All checks were successful
ci/cd / Build (push) Successful in 5s
2025-05-05 20:56:41 +02:00
0619ff0693 Added datatjej
All checks were successful
ci/cd / Build (push) Successful in 6s
2025-05-05 20:53:48 +02:00
6b263f340e added bg
All checks were successful
ci/cd / Build (push) Successful in 6s
2025-05-05 20:45:28 +02:00
8ff494c616 update experience
All checks were successful
ci/cd / Build (push) Successful in 6s
2025-05-05 20:39:49 +02:00
98251fcf78 update docker file
All checks were successful
ci/cd / Build (push) Successful in 13s
2025-05-05 20:30:53 +02:00
2ce2aa3d23 remove spline
Some checks failed
ci/cd / Build (push) Failing after 8s
2025-05-05 20:27:39 +02:00
44c68e68e9 dockerfile
Some checks failed
ci/cd / Build (push) Failing after 3s
2025-05-05 20:21:18 +02:00
ec35f4c954 update about page
Some checks failed
ci/cd / Build (push) Failing after 3s
2025-05-05 20:17:02 +02:00
6a6c24ab20 refactor: update project layout and descriptions - Move project title to top - Simplify project descriptions - Adjust layout for better readability
Some checks failed
ci/cd / Build (push) Failing after 11s
2025-05-05 20:12:43 +02:00
055975162a
update UI
All checks were successful
ci/cd / Build (push) Successful in 10s
2024-10-14 14:53:11 +02:00
bae2d2b680
target
All checks were successful
ci/cd / Build (push) Successful in 6s
2024-09-25 13:58:59 +02:00
69d4b4f59e
added linkedin
All checks were successful
ci/cd / Build (push) Successful in 7s
2024-09-25 13:58:33 +02:00
1d4d70c26c
Update CI
All checks were successful
ci/cd / Build (push) Successful in 7s
2024-09-25 13:44:52 +02:00
a75027d8fa
Update deploy script
Some checks failed
ci/cd / Build (push) Failing after 8s
2024-09-25 13:41:10 +02:00
f32c26bb7d
UI update
Some checks failed
ci/cd / Build (push) Failing after 1s
2024-09-25 13:34:57 +02:00
1668da060a
update
Some checks failed
ci/cd / Build (push) Failing after 14s
2024-02-04 22:31:04 +01:00
019b1ad4e7
update text about 2024-02-04 22:30:33 +01:00
85f23f5288
update fonts
Some checks failed
ci/cd / Build (push) Failing after 8s
2024-01-08 23:36:42 +01:00
51fb14784d
undo
Some checks failed
ci/cd / Build (push) Failing after 4s
2024-01-08 19:17:57 +01:00
4a4372a36d Update title
Some checks failed
ci/cd / Build (push) Failing after 10s
2024-01-08 19:09:49 +01:00
Mariia Shabelnik
21f20a93a3 update imgs size
All checks were successful
ci/cd / Build (push) Successful in 9s
2024-01-08 18:43:39 +01:00
Mariia Shabelnik
b34b33215b changed domain name
All checks were successful
ci/cd / Build (push) Successful in 15s
2024-01-08 18:24:04 +01:00
Mariia Shabelnik
368dce10e7 Merge branch 'release/v1' into develop
All checks were successful
ci/cd / Build (push) Successful in 9s
2024-01-08 12:11:55 +01:00
37 changed files with 2690 additions and 2937 deletions

View File

@ -7,12 +7,12 @@ jobs:
runs-on: all runs-on: all
steps: steps:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Declare variables - name: Declare variables
run: | run: |
echo "sha_short=$(git rev-parse --short "$GITHUB_SHA")" >> "$GITHUB_ENV" echo "sha_short=$(git rev-parse --short "$GITHUB_SHA")" >> "$GITHUB_ENV"
echo "run_name=$(echo "$GITHUB_REPOSITORY" | sed "s/\//_/")" >> "$GITHUB_ENV" echo "run_name=$(echo "$GITHUB_REPOSITORY" | sed "s/\//_/")" >> "$GITHUB_ENV"
echo "domain_name="www.mariia.art"" >> "$GITHUB_ENV" echo "domain_name="www.msweb.io"" >> "$GITHUB_ENV"
echo "docker_port="80"" >> "$GITHUB_ENV" echo "docker_port="80"" >> "$GITHUB_ENV"
- name: Build docker - name: Build docker
run: | run: |
@ -21,8 +21,4 @@ jobs:
run: | run: |
docker container rm -f ${{ env.run_name }} || true docker container rm -f ${{ env.run_name }} || true
docker run -d --network=web --restart unless-stopped --name ${{ env.run_name }} ${{ gitea.repository }}:${{ env.sha_short }} docker run -d --network=web --restart unless-stopped --name ${{ env.run_name }} ${{ gitea.repository }}:${{ env.sha_short }}
/usr/local/bin/caddycontrol -host ${{ env.domain_name }} -dial ${{ env.run_name }}:${{ env.docker_port }} /usr/bin/caddyconf --add --url ${{ env.domain_name }} --name ${{ env.run_name }} --port ${{ env.docker_port }}

View File

@ -1,14 +1,12 @@
FROM node:17.1.0-alpine3.12 as builder FROM node:20-alpine AS builder
WORKDIR /app WORKDIR /app
COPY package.json ./ COPY package*.json ./
COPY package-lock.json ./ RUN npm install
RUN npm install COPY . .
COPY ./ ./ RUN npm run build
RUN NODE_ENV=production npm run build
FROM caddy:2-alpine FROM caddy:2-alpine
WORKDIR /usr/share/caddy WORKDIR /usr/share/caddy
COPY Caddyfile /etc/caddy/Caddyfile COPY Caddyfile /etc/caddy/Caddyfile
COPY --from=builder ./app/dist . COPY --from=builder /app/dist .

View File

@ -2,27 +2,43 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=5.0"
/>
<meta
name="description"
content="Mariia Shabelnik - Frontend Engineer portfolio showcasing web development projects and skills"
/>
<meta name="theme-color" content="#f0f0f3" />
<link <link
rel="icon" rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22> 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 y=%22.9em%22 font-size=%2290%22> 🫰
👋
</text> </text>
</svg>" </svg>"
/> />
<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.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- nav font -->
<link <link
href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&display=swap" href="https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet" rel="stylesheet"
/> />
<!-- body font -->
<link <link
href="https://fonts.googleapis.com/css2?family=Ubuntu+Mono:wght@400;700&display=swap" href="https://fonts.googleapis.com/css2?family=Jura:wght@300..700&display=swap"
rel="stylesheet" rel="stylesheet"
/> />
<!-- headline-title font -->
<link <link
href="https://fonts.googleapis.com/css2?family=Tektur:wght@400;500;600;700;800;900&display=swap" href="https://fonts.googleapis.com/css2?family=Sora:wght@100..800&display=swap"
rel="stylesheet"
/>
<!-- logo font -->
<link
href="https://fonts.googleapis.com/css2?family=Sixtyfour&display=swap"
rel="stylesheet" rel="stylesheet"
/> />

4696
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,11 +9,13 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"framer-motion": "^12.9.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-icons": "^4.12.0",
"react-image-gallery": "^1.3.0", "react-image-gallery": "^1.3.0",
"react-intersection-observer": "^9.16.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",
"recoil": "^0.7.7" "recoil": "^0.7.7"
@ -21,10 +23,10 @@
"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": "^4.4.1",
"autoprefixer": "^10.4.15", "autoprefixer": "^10.4.15",
"postcss": "^8.4.29", "postcss": "^8.4.29",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",
"vite": "^3.0.0" "vite": "^6.3.5"
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
public/img/ProfileMe.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#0288D1" d="M42,37c0,2.762-2.238,5-5,5H11c-2.761,0-5-2.238-5-5V11c0-2.762,2.239-5,5-5h26c2.762,0,5,2.238,5,5V37z"/><path fill="#FFF" d="M12 19H17V36H12zM14.485 17h-.028C12.965 17 12 15.888 12 14.499 12 13.08 12.995 12 14.514 12c1.521 0 2.458 1.08 2.486 2.499C17 15.887 16.035 17 14.485 17zM36 36h-5v-9.099c0-2.198-1.225-3.698-3.192-3.698-1.501 0-2.313 1.012-2.707 1.99C24.957 25.543 25 26.511 25 27v9h-5V19h5v2.616C25.721 20.5 26.85 19 29.738 19c3.578 0 6.261 2.25 6.261 7.274L36 36 36 36z"/></svg>

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 KiB

After

Width:  |  Height:  |  Size: 139 KiB

BIN
public/img/mockup_net0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

After

Width:  |  Height:  |  Size: 584 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 234 KiB

BIN
public/img/oreo-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -1,20 +1,18 @@
//import "./App.css"; //import "./App.css";
import { Routes, Route } from "react-router-dom"; import { Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import Experience from "./pages/Experience";
import Contact from "./pages/Contact";
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 FullPage from "./pages/FullPage";
import { RecoilRoot } from "recoil"; import { RecoilRoot } from "recoil";
import ScrollToAnchor from "./components/ScrollToAnchor"; import ScrollToAnchor from "./components/ScrollToAnchor";
import AnimatedBackground from "./components/AnimatedBackground";
function App() { function App() {
return ( return (
<div className="text-white"> <div className="text-gray-600">
<AnimatedBackground />
<RecoilRoot> <RecoilRoot>
<main className=" min-h-screen"> <main className="min-h-screen">
<Header /> <Header />
<ScrollToAnchor /> <ScrollToAnchor />
<Routes> <Routes>
@ -23,7 +21,6 @@ function App() {
<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 />
</main> </main>
</RecoilRoot> </RecoilRoot>
</div> </div>

View File

@ -0,0 +1,97 @@
import { useEffect, useRef } from 'react';
const AnimatedBackground = () => {
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
let animationFrameId;
let lastScrollY = 0;
// Set canvas size
const resizeCanvas = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Create dots
const dots = [];
const dotCount = 80; // Reduced from 100 for smoother performance
for (let i = 0; i < dotCount; i++) {
dots.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
size: Math.random() * 2 + 1,
speed: Math.random() * 0.3 + 0.1, // Reduced speed for smoother movement
});
}
// Animation loop
const animate = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw dots
ctx.fillStyle = 'rgba(150, 150, 150, 0.3)'; // Increased from 0.2
dots.forEach(dot => {
ctx.beginPath();
ctx.arc(dot.x, dot.y, dot.size * 1.2, 0, Math.PI * 2); // Increased size
ctx.fill();
});
// Draw connections
ctx.strokeStyle = 'rgba(150, 150, 150, 0.15)'; // Increased from 0.1
ctx.lineWidth = 1; // Increased from 0.8
dots.forEach((dot1, i) => {
dots.slice(i + 1).forEach(dot2 => {
const dx = dot1.x - dot2.x;
const dy = dot1.y - dot2.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 180) { // Increased connection distance
ctx.beginPath();
ctx.moveTo(dot1.x, dot1.y);
ctx.lineTo(dot2.x, dot2.y);
ctx.stroke();
}
});
});
animationFrameId = requestAnimationFrame(animate);
};
// Handle scroll
const handleScroll = () => {
const scrollY = window.scrollY;
const scrollDiff = scrollY - lastScrollY;
dots.forEach(dot => {
dot.y += scrollDiff * dot.speed * 0.15; // Reduced movement speed
if (dot.y > canvas.height) dot.y = 0;
if (dot.y < 0) dot.y = canvas.height;
});
lastScrollY = scrollY;
};
window.addEventListener('scroll', handleScroll);
animate();
// Cleanup
return () => {
window.removeEventListener('resize', resizeCanvas);
window.removeEventListener('scroll', handleScroll);
cancelAnimationFrame(animationFrameId);
};
}, []);
return (
<canvas
ref={canvasRef}
className="fixed top-0 left-0 w-full h-full pointer-events-none -z-10"
/>
);
};
export default AnimatedBackground;

View File

@ -1,9 +1,34 @@
import { FaLinkedin, FaEnvelope } from "react-icons/fa";
function Footer() { function Footer() {
const fullYear = new Date().getFullYear(); const fullYear = new Date().getFullYear();
const email = "mariia.shabelnik@gmail.com"; // Replace with your email
const linkedinUrl = "https://www.linkedin.com/in/mariia-shabelnik/"; // Replace with your LinkedIn URL
return ( return (
<footer className="container mx-auto my-10 px-6 sticky top-[95vh]"> <footer className="container mx-auto my-10 px-6 sticky top-[95vh]">
<div className=" text-center text-sm text-white/50 "> <div className="flex flex-col items-center gap-4">
© {fullYear} Mariia Shabelnik, all rights reserved <div className="flex gap-6">
<a
href={`mailto:${email}`}
className="text-gray-500 hover:text-highlight transition-colors duration-300"
aria-label="Send email to Mariia"
>
<FaEnvelope className="w-6 h-6" />
</a>
<a
href={linkedinUrl}
target="_blank"
rel="noopener noreferrer"
className="text-gray-500 hover:text-highlight transition-colors duration-300"
aria-label="Visit Mariia's LinkedIn profile"
>
<FaLinkedin className="w-6 h-6" />
</a>
</div>
<div className="text-center text-sm text-gray-500">
© {fullYear} Mariia Shabelnik, all rights reserved
</div>
</div> </div>
</footer> </footer>
); );

View File

@ -13,17 +13,17 @@ function Header() {
}, [isOpen]); }, [isOpen]);
const menu = [ const menu = [
{ link: "/#about", title: ".me()" }, { link: "/#about", title: ".about( )" },
{ link: "/#experience", title: ".experience()" }, { link: "/#experience", title: ".projects( )" },
{ link: "/#contact", title: ".contact()" }, { link: "/#contact", title: ".contact( )" },
]; ];
const menuUI = menu.map((item) => { const menuUI = menu.map((item) => {
let className = "drop-shadow-light hover:drop-shadow-doublelight"; let className = "drop-shadow-doublelight hover:drop-shadow-active";
if (location.pathname === item.link) { if (`/${location.hash}` === item.link) {
className += " text-white"; className += " text-white";
} else { } else {
className += " text-white/40"; className += " text-gray-500";
} }
return ( return (
<li className="my-10 text-xl md:my-0 md:text-base" key={item.link}> <li className="my-10 text-xl md:my-0 md:text-base" key={item.link}>
@ -33,6 +33,9 @@ function Header() {
setOpen(false); setOpen(false);
}} }}
to={item.link} to={item.link}
aria-current={
location.hash === item.link.slice(2) ? "page" : undefined
}
> >
{item.title} {item.title}
</Link> </Link>
@ -40,10 +43,19 @@ function Header() {
); );
}); });
const headerClasses = ["sticky", "top-0", "z-40", "backdrop-blur-md", "h-16"]; const headerClasses = [
"sticky",
"top-0",
"z-40",
"backdrop-blur-sm",
"h-16",
"border-b-[1px]",
"border-white",
"rounded-b-[1rem]",
];
const logoClasses = ["hover:drop-shadow-light"]; const logoClasses = ["hover:drop-shadow-light"];
const overlayMenu = [ const overlayMenu = [
"bg-black/90", "bg-white/90",
"z-50", "z-50",
"fixed", "fixed",
"left-0", "left-0",
@ -54,37 +66,64 @@ function Header() {
"p-2", "p-2",
]; ];
if (isOpen) { if (isOpen) {
headerClasses.push("bg-black/90"); headerClasses.push("bg-white/70");
logoClasses.push("drop-shadow-yellow"); logoClasses.push("drop-shadow-gray");
} else { } else {
headerClasses.push("bg-bgColor/90"); headerClasses.push("bg-bgColor/70");
logoClasses.push("drop-shadow-doublelight"); logoClasses.push("drop-shadow-active");
} }
return ( return (
<> <>
{isOpen && ( {isOpen && (
<div className={overlayMenu.join(" ")}> <nav
<div className=" h-[calc(100vh-20rem)] flex flex-col justify-center"> className={overlayMenu.join(" ")}
<ul>{menuUI}</ul> aria-label="Mobile navigation menu"
role="navigation"
>
<div className="h-[calc(100vh-20rem)] flex flex-col justify-center">
<ul role="menu" aria-label="Mobile menu items">
{menuUI}
</ul>
</div> </div>
</div> </nav>
)} )}
<header className={headerClasses.join(" ")}> <header className={headerClasses.join(" ")}>
<div className="container mx-auto h-full"> <div className="container mx-auto h-full max-w-7xl">
<nav className="flex items-center h-full px-2"> <nav
<div className="flex-none text-3xl md:text-4xl font-black font-headline "> className="flex items-center h-full px-10"
<Link className={logoClasses.join(" ")} to="/#start"> aria-label="Main navigation"
MS. role="navigation"
>
<div className="flex-none text-3xl md:text-4xl font-logo text-[#6d6d6d]">
<Link
className={logoClasses.join(" ")}
to="/#start"
aria-label="Home"
>
MS
</Link> </Link>
</div> </div>
<div className="grow"></div> <div className="grow"></div>
<div className="flex-none hidden md:block "> <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"
role="menu"
aria-label="Main menu items"
>
{menuUI}
</ul>
</div> </div>
<div className="flex-none block md:hidden"> <div className="flex-none block md:hidden">
<Hamburger toggled={isOpen} toggle={setOpen} duration={0.9} /> <Hamburger
toggled={isOpen}
toggle={setOpen}
duration={0.9}
aria-label="Toggle mobile menu"
aria-expanded={isOpen}
aria-controls="mobile-menu"
/>
</div> </div>
</nav> </nav>
</div> </div>

View File

@ -0,0 +1,20 @@
import React from "react";
import { GoChevronLeft } from "react-icons/go";
const LeftNav = React.memo(({ disabled, onClick }) => {
return (
<button
type="button"
className="image-gallery-icon image-gallery-left-nav text-2xl md:text-4xl text-highlight"
disabled={disabled}
onClick={onClick}
aria-label="Previous Slide"
>
<GoChevronLeft />
</button>
);
});
LeftNav.displayName = "LeftNav";
export default LeftNav;

View File

@ -0,0 +1,25 @@
import React from "react";
// import { bool, func } from "prop-types";
// import SVG from "src/components/SVG";
const PlayPause = React.memo(({ isPlaying, onClick }) => {
return (
<button
type="button"
className="image-gallery-icon image-gallery-play-button"
onClick={onClick}
aria-label="Play or Pause Slideshow"
>
<SVG strokeWidth={2} icon={isPlaying ? "pause" : "play"} />
</button>
);
});
PlayPause.displayName = "PlayPause";
// PlayPause.propTypes = {
// isPlaying: bool.isRequired,
// onClick: func.isRequired,
// };
export default PlayPause;

View File

@ -0,0 +1,19 @@
import React from "react";
import { GoChevronRight } from "react-icons/go";
const RightNav = React.memo(({ disabled, onClick }) => {
return (
<button
type="button"
className="image-gallery-icon image-gallery-right-nav text-2xl md:text-4xl text-highlight"
disabled={disabled}
onClick={onClick}
aria-label="Next Slide"
>
<GoChevronRight />
</button>
);
});
RightNav.displayName = "RightNav";
export default RightNav;

View File

@ -9,10 +9,17 @@ function ScrollToAnchor() {
// https://jasonwatmore.com/react-router-v6-listen-to-location-route-change-without-history-listen // https://jasonwatmore.com/react-router-v6-listen-to-location-route-change-without-history-listen
useEffect(() => { useEffect(() => {
if (location.hash) { if (location.hash) {
lastHash.current = location.hash.slice(1); // safe hash for further use after navigation lastHash.current = location.hash.slice(1);
} }
if (lastHash.current && document.getElementById(lastHash.current)) { if (lastHash.current === "contact") {
// Scroll to bottom of the page
window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: "smooth"
});
lastHash.current = "";
} else if (lastHash.current && document.getElementById(lastHash.current)) {
setTimeout(() => { setTimeout(() => {
document document
.getElementById(lastHash.current) .getElementById(lastHash.current)

View File

@ -1,13 +1,16 @@
function Tags({ listOfTags }) { function Tags({ listOfTags }) {
const tagList = listOfTags.map((itemTag, keyTag) => { const tagList = listOfTags.map((itemTag, keyTag) => {
return ( return (
<div className={`bg-gray-800 py-1 px-2 rounded-xl `} key={keyTag}> <div
className="bg-gray-500 py-1 px-2 rounded-xl shadow-md hover:shadow-lg transition-shadow duration-200 hover:bg-gray-600"
key={keyTag}
>
{itemTag} {itemTag}
</div> </div>
); );
}); });
return ( return (
<div className="text-tags flex flex-wrap gap-2 font-tags text-highlight "> <div className="text-tags flex flex-wrap gap-2 font-tags text-white">
{tagList} {tagList}
</div> </div>
); );

View File

@ -4,8 +4,8 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
body { body {
background-color: #031417; background-color: #f0f0f3;
} }
::selection { ::selection {
background: #7d9c00b1; background: #caebfa;
} }

View File

@ -1,40 +1,115 @@
import { useRecoilValue } from "recoil"; import { useRecoilValue } from "recoil";
import Tags from "../components/Tags"; import Tags from "../components/Tags";
import { skillsAtom } from "../store"; import { skillsAtom } from "../store";
import { motion } from "framer-motion";
import { useInView } from "react-intersection-observer";
function About() { function About() {
const skills = useRecoilValue(skillsAtom); const skills = useRecoilValue(skillsAtom);
console.log(skills); const [ref, inView] = useInView({
triggerOnce: true,
threshold: 0.1,
});
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.5,
ease: "easeOut",
},
},
};
return ( return (
<div className="relative"> <section className="relative" aria-labelledby="about-heading">
<div id="about" className=" absolute -top-16 "></div> <div id="about" className="absolute"></div>
<h2 className="mb-2 text-subTPhone md:text-subT font-headline"> <div className="min-h-screen flex items-center">
About<span className=" text-highlight">.</span> <motion.div
</h2> ref={ref}
<div className="flex flex-col md:flex-row"> variants={containerVariants}
<div className="basis-2/3 text-base"> initial="hidden"
<p> animate={inView ? "visible" : "hidden"}
As a prospective Frontend Developer, I seek a challenging career >
opportunity in the IT industry, where I can collaborate with a <motion.h2
dynamic team, continually learn, and foster innovation. My variants={itemVariants}
dedication lies in transforming design concepts into user-friendly id="about-heading"
experiences and achieving organizational goals through creativity className="mb-6 text-subTPhone md:text-subT font-headline"
and teamwork. I aspire to engage in work that allows the utilization >
of technical and creative skills to contribute effectively to the About me<span className="text-highlight">.</span>
growth of an organization. If you think you've got an opening that I </motion.h2>
might like, let's connect 🔗 <motion.div variants={itemVariants} className="flex flex-col md:flex-row gap-6">
</p> <motion.article variants={itemVariants} className="basis-6/12 text-base font-body">
</div> <p>
<div className=" basis-1/3"> "I'm a Stockholm-based developer passionate about building
<h4 className="mb-2 text-subTMini">Languages:</h4> innovative, secure digital experiences with a focus on both
<Tags listOfTags={skills.languages} /> frontend and backend technologies. With expertise in JavaScript,
<h4 className="my-2 text-subTMini">Frameworks:</h4>{" "} React, TypeScript, and a keen eye for web design, I create
<Tags listOfTags={skills.frameworks} /> solutions that combine functionality with creativity. I use
<h4 className="my-2 text-subTMini">Tools I use:</h4>{" "} Node.js for backend development and SQL for database management,
<Tags listOfTags={skills.tools} /> ensuring my applications are both robust and scalable. I also
</div> have a deep passion for 3D design, which adds a unique,
immersive dimension to my work. I thrive in collaborative
environments that encourage continuous learning and value
creative problem-solving. Let's collaborate to push the
boundaries of digital innovation!"
{/* As a prospective Frontend Developer, I seek a challenging career
opportunity in the IT industry, where I can collaborate with a
dynamic team, continually learn, and foster innovation. My
dedication lies in transforming design concepts into
user-friendly experiences and achieving organizational goals
through creativity and teamwork. I aspire to engage in work that
allows the utilization of technical and creative skills to
contribute effectively to the growth of an organization. If you
think you've got an opening that I might like, let's connect 🔗 */}
</p>
</motion.article>
<motion.figure variants={itemVariants} className="border">
<img
className="rounded-3xl"
src="/img/ProfileMe.jpg"
alt="Mariia Shabelnik's profile photo"
/>
</motion.figure>
<motion.aside variants={itemVariants} className="basis-1/3" aria-labelledby="skills-heading">
<h2 id="skills-heading" className="sr-only">
Skills and Technologies
</h2>
<section aria-labelledby="languages-heading">
<h3 id="languages-heading" className="mb-2 text-subTMini">
Languages:
</h3>
<Tags listOfTags={skills.languages} />
</section>
<section aria-labelledby="frameworks-heading">
<h3 id="frameworks-heading" className="my-2 text-subTMini">
Frameworks:
</h3>
<Tags listOfTags={skills.frameworks} />
</section>
<section aria-labelledby="tools-heading">
<h3 id="tools-heading" className="my-2 text-subTMini">
Tools I use:
</h3>
<Tags listOfTags={skills.tools} />
</section>
</motion.aside>
</motion.div>
</motion.div>
</div> </div>
</div> </section>
); );
} }

View File

@ -2,7 +2,8 @@ function Contact() {
return ( return (
<div className="relative"> <div className="relative">
<div id="contact" className=" absolute -top-16 "></div> <div id="contact" className=" absolute -top-16 "></div>
<h1>Welcome to C#ontact</h1> <h1>Contact me</h1>
<p></p>
</div> </div>
); );
} }

View File

@ -2,62 +2,105 @@ import { Link } from "react-router-dom";
import { useRecoilValue } from "recoil"; import { useRecoilValue } from "recoil";
import { projectsAtom } from "../store"; import { projectsAtom } from "../store";
import Tags from "../components/Tags"; import Tags from "../components/Tags";
import { motion } from "framer-motion";
import { useInView } from "react-intersection-observer";
function Experiance() { function Experiance() {
const experianceList = useRecoilValue(projectsAtom); const experianceList = useRecoilValue(projectsAtom);
const [ref, inView] = useInView({
triggerOnce: true,
threshold: 0.1,
});
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.5,
ease: "easeOut",
},
},
};
const experianceListUI = experianceList.map((item, key) => { const experianceListUI = experianceList.map((item, key) => {
const position = key % 2; const even = key % 2;
const imgClasses = ["basis-1/3", "hidden", "md:block"];
if (position === 1) {
imgClasses.push("md:order-last");
}
return ( return (
<section className="flex flex-col md:flex-row gap-4 mb-12" key={item.id}> <motion.article
<div className={imgClasses.join(" ")}> ref={ref}
<img className="rounded-md" src={item.img[0]} /> variants={itemVariants}
</div> className={`flex-1 gap-4 mb-12 bg-[#f0f0f3] border shadow-box ${
<div className="basis-2/3 flex flex-col"> (even === 0 && "rounded-tl-3xl rounded-br-3xl") ||
<div> "rounded-tr-3xl rounded-bl-3xl"
<h2 className="text-subTMiniPhone md:text-subTMini mb-4 "> }`}
key={item.id}
>
<div className={`flex pt-4 md:pt-14 flex-col `}>
<div className="px-4 mb-4">
<h3 className="text-subTMiniPhone md:text-subTMini font-ht">
{item.title} {item.title}
</h2> </h3>
</div> </div>
<div> <figure className="basis-5/12">
<img <img
className="block md:hidden mb-4 rounded-md" className="w-full"
src={item.img[0]} src={item.img[0]}
alt={`Preview of ${item.title} project`}
/> />
</div> </figure>
<div className="text-base mb-6 line-clamp-3 md:line-clamp-6">
<p>{item.info}</p>
</div>
<Tags listOfTags={item.tags} />
<div className="grow"></div> <div className="grow"></div>
<div className=" text-right"> <div className="flex flex-col px-4 pt-4 pb-8 basis-3/12">
<Link <div className="mb-4">
className=" drop-shadow-doublelight hover:drop-shadow-light " <Tags listOfTags={item.tags} />
to={`/experience/${item.id}`} </div>
>
read more <div className="text-base mb-6">
</Link> <p>{item.info}</p>
</div>
</div> </div>
</div> </div>
</section> </motion.article>
); );
}); });
return ( return (
<div className="relative"> <section className="relative" aria-labelledby="projects-heading">
<div id="experience" className=" absolute -top-16 "></div> <div
<h2 className=" text-subTPhone md:text-subT font-headline"> id="experience"
Experience<span className=" text-highlight">.</span> className="absolute -top-16"
</h2> aria-hidden="true"
<div className="py-4">{experianceListUI}</div> ></div>
</div> <div className="min-h-screen">
<h2
id="projects-heading"
className="text-subTPhone md:text-subT font-headline mb-6"
>
Projects and experience<span className="text-highlight">.</span>
</h2>
<motion.div
ref={ref}
variants={containerVariants}
initial="hidden"
animate={inView ? "visible" : "hidden"}
className="py-4 grid grid-cols-1 md:grid-cols-2 gap-8"
>
{experianceListUI}
</motion.div>
</div>
</section>
); );
} }

View File

@ -4,6 +4,8 @@ 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"; import { IoChevronBackOutline as BackButton } from "react-icons/io5";
import LeftNav from "../components/LeftNav";
import RightNav from "../components/RightNav";
function ExperianceDetail() { function ExperianceDetail() {
const { id } = useParams(); const { id } = useParams();
@ -48,16 +50,16 @@ function ExperianceDetail() {
</button> </button>
<div className="flex flex-col"> <div className="flex flex-col">
<div className="flex-1"> <div className="flex-1">
<h1 className=" text-subTPhone md:text-subT"> <h1 className="text-subTPhone md:text-subT font-headline">
Project: {myProject.title} Project: {myProject.title}
</h1> </h1>
</div> </div>
<div className="flex-1 mt-2 mb-6"> <div className="flex-1 mt-2 mb-6 min-h-[80px]">
<Tags listOfTags={myProject.tags} /> <Tags listOfTags={myProject.tags} />
</div>{" "} </div>
</div> </div>
<div className="flex flex-col md:flex-row gap-4"> <div className="flex flex-col md:flex-row gap-8">
<div className="flex-1"> <div className="w-full md:w-1/2">
<ImageGallery <ImageGallery
showThumbnails={false} showThumbnails={false}
showBullets={true} showBullets={true}
@ -65,11 +67,20 @@ function ExperianceDetail() {
slideDuration={1000} slideDuration={1000}
slideInterval={4000} slideInterval={4000}
items={projectImg} items={projectImg}
renderLeftNav={(onClick, disabled) => (
<LeftNav onClick={onClick} disabled={disabled} />
)}
renderRightNav={(onClick, disabled) => (
<RightNav onClick={onClick} disabled={disabled} />
)}
/> />
</div> </div>
<div className="flex-1 text-base"> <div className="w-full md:w-1/2 flex flex-col min-h-[300px]">
{myProject.info} <div className="flex-1">
<div className=" drop-shadow-doublelight hover:drop-shadow-light my-2 text-end"> <h2 className="text-xl font-semibold mb-4">{myProject.subtitle}</h2>
<p className="text-base leading-relaxed">{myProject.description}</p>
</div>
<div className="drop-shadow-doublelight hover:drop-shadow-light my-2 text-end">
{linkUI} {linkUI}
</div> </div>
</div> </div>

View File

@ -1,15 +1,15 @@
import About from "./About"; import About from "./About";
import Contact from "./Contact"; import Footer from "../components/Footer";
import Experiance from "./Experience"; import Experiance from "./Experience";
import Start from "./Start"; import Start from "./Start";
function FullPage() { function FullPage() {
return ( return (
<div className="container mx-auto px-2"> <div className="container mx-auto px-10 max-w-6xl">
<Start /> <Start />
<About /> <About />
<Experiance /> <Experiance />
<Contact /> <Footer />
</div> </div>
); );
} }

View File

@ -1,78 +0,0 @@
import {
Animator,
ScrollContainer,
ScrollPage,
batch,
Fade,
FadeIn,
FadeOut,
Move,
MoveIn,
MoveOut,
Sticky,
StickyIn,
StickyOut,
Zoom,
ZoomIn,
ZoomOut,
} from "react-scroll-motion";
function Home() {
const ZoomInScrollOut = batch(StickyIn(), FadeIn(), ZoomIn());
const FadeUp = batch(Fade(), Move(), Sticky());
return (
<ScrollContainer>
<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>
</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>
);
}
export default Home;

View File

@ -1,23 +1,110 @@
import { motion, useAnimation } from "framer-motion";
import { useEffect } from "react";
function Start() { function Start() {
const greeting = "Hello, my name is Maria.";
const greetingArray = greeting.split("");
const role = "I'm a Frontend Engineer.";
const roleArray = role.split("");
const controls = useAnimation();
const contentControls = useAnimation();
useEffect(() => {
// Start the second animation after the first line completes
const timer1 = setTimeout(() => {
controls.start("visible");
}, greetingArray.length * 100 + 500); // Total time for first line + 500ms delay
// Start the content animation after the second line completes
const timer2 = setTimeout(() => {
contentControls.start("visible");
}, (greetingArray.length + roleArray.length) * 100 + 1000); // Total time for both lines + 1000ms delay
return () => {
clearTimeout(timer1);
clearTimeout(timer2);
};
}, []);
return ( return (
<div className="relative"> <div className="relative">
<div id="start" className="absolute -top-16 "></div> <div id="start" className="absolute -top-16 "></div>
<div> <div className=" min-h-screen flex items-center">
<h1 className="text-titlePhone md:text-title md:leading-tight mb-2 font-headline"> <div className="">
Hello, my name is Maria<span className=" text-highlight">.</span> <h1 className="text-titlePhone md:text-title md:leading-tight mb-2 font-ht">
</h1> {greetingArray.map((letter, index) => (
<h2 className="text-subTPhone md:text-subT font-headline"> <motion.span
I'm a<span className=" text-highlight"> Frontend Engineer</span> key={index}
</h2> initial={{ opacity: 0 }}
<p className="text-base"> animate={{ opacity: 1 }}
In my recent journey as a junior frontend engineer, I've gained transition={{
valuable experience through involvement in various projects within duration: 0.1,
startup environments. Passionate about art and design, I've developed delay: index * 0.1,
my skills beyond coding. Let's connect and explore opportunities }}
together! By the way, you might catch a glimpse of my black mini >
poodle, Oreo, who's an integral part of my creative space. {letter}
</p> </motion.span>
))}
</h1>
<h2 className="text-subTPhone md:text-subT font-ht">
{roleArray.map((letter, index) => (
<motion.span
key={index}
initial={{ opacity: 0 }}
animate={controls}
variants={{
visible: { opacity: 1 }
}}
transition={{
duration: 0.1,
delay: index * 0.1,
}}
>
{letter}
</motion.span>
))}
</h2>
<motion.div
initial={{ opacity: 0 }}
animate={contentControls}
variants={{
visible: { opacity: 1 }
}}
transition={{
duration: 0.8,
ease: "easeOut"
}}
>
<p className="text-base md:w-1/2 w-full text-left my-4 font-body">
I'm a Stockholm-based web developer with startup experience,
building things with JavaScript, React, and Node.js. I'm also into
3D design and art, and my mini poodle,{" "}
<span className="font-black">Oreo</span>{" "}
<img
src="/img/oreo-logo.png"
alt="oreo_logo"
className="inline h-"
/>{" "}
, is always in my creative space. Let's chat!
</p>
<div>
<a
href="https://www.linkedin.com/in/mariia-shabelnik/"
target="_blank"
className="flex items-center gap-2 hover:text-highlight transition-colors duration-300"
>
<img
src="/img/icons8-linkedin.svg"
alt="LinkedIn icon"
className="inline h-6"
/>
LinkedIn
</a>
</div>
</motion.div>
</div>
</div> </div>
</div> </div>
); );

View File

@ -4,8 +4,10 @@ const experianceList = [
{ {
id: "46bf76ae-8915-4e5d-ae92-4151be80e75a", id: "46bf76ae-8915-4e5d-ae92-4151be80e75a",
title: "Netzero web", title: "Netzero web",
info: "Discover the intersection of sustainability and technology in my collaboration with Net0. As the creative force behind the UI/UX design, I meticulously crafted a seamless and visually appealing user experience. Bringing this vision to life, I also spearheaded the frontend development, using React to construct an intuitive and efficient system for Net0. Immerse yourself in the synergy of eco-conscious practices and cutting-edge technology as we navigate towards a greener future, one React component at a time.", subtitle: "Lead UI/UX Designer & Frontend Developer",
info: "As the lead UI/UX designer and frontend developer for Net0's sustainability platform, I spearheaded the creation of an intuitive system that seamlessly integrates eco-conscious practices with modern technology. Built with React and TypeScript, the platform features a comprehensive dashboard for tracking carbon emissions, implementing sustainable practices, and generating detailed reports. I collaborated closely with the backend team to ensure smooth integration with the Node.js and PostgreSQL infrastructure, while maintaining a strong focus on user experience and accessibility throughout the development process.",
img: ["/img/net0_0.png", "/img/net0_1.png", "/img/net0_2.png"], img: ["/img/net0_0.png", "/img/net0_1.png", "/img/net0_2.png"],
previewImg: "/img/mockup_net0.png",
tags: [ tags: [
"React", "React",
"Vite", "Vite",
@ -19,18 +21,47 @@ const experianceList = [
"Javascript", "Javascript",
], ],
link: "https://www.net0.se", link: "https://www.net0.se",
sortOrder: 2
}, },
{ {
id: "55515a25-deb1-451c-bc7d-006d293f54aa", id: "55515a25-deb1-451c-bc7d-006d293f54aa",
title: "Lets fly", title: "Lets fly",
info: "Letsfly is a website aimed at providing a platform for aviation-related services and information. Built on Next.js, a popular React framework, the website leverages its server-side rendering (SSR) capability to enhance performance and user experience. Tailwind was used as the CSS framework to quickly and efficiently create an attractive and responsive design. WordPress, a well-known Content Management System (CMS), was employed as the content management system to administer and publish content on the website. The reason for choosing WordPress was a client request; he was familiar with this system and wanted to be able to modify the content himself. GraphQL was selected as the API layer to enable efficient data management and flexible data queries between the frontend and backend.", subtitle: "Full Stack Developer",
info: "Developed a comprehensive aviation services platform using Next.js and WordPress, focusing on creating a seamless experience for both service providers and clients. Implemented GraphQL for efficient data management and real-time updates, while utilizing Tailwind CSS for responsive and modern design. The platform features a sophisticated booking system, real-time availability tracking, and integrated payment processing. I worked closely with the client to ensure the WordPress integration met their specific requirements while maintaining high performance and security standards throughout the development process.",
img: ["/img/letsfly_1.png", "/img/letsfly_2.png", "/img/letsfly_3.png"], img: ["/img/letsfly_1.png", "/img/letsfly_2.png", "/img/letsfly_3.png"],
tags: ["React", "NextJS", "Wordpress", "GraphQL", "MySQL", "Tailwind"], tags: ["React", "NextJS", "Wordpress", "GraphQL", "MySQL", "Tailwind"],
link: "https://preview.letsfly.app/", link: "https://preview.letsfly.app/",
previewImg: "/img/mockup_net0.png",
sortOrder: 3
}, },
{
id: 4,
title: "DataTjej",
subtitle: "Board Member & Web Developer",
info: "As a board member of DataTjej, I'm actively involved in shaping the future of this non-profit organization that supports women and non-binary individuals in tech. Currently leading the development of a new website using Next.js and Tailwind CSS, focusing on creating a modern, accessible platform. The project includes automating connections to various solutions like our podcast and event management systems, streamlining our digital presence and member engagement.",
img: ["/images/datatjej-placeholder.jpg"],
previewImg: "/images/datatjej-placeholder.jpg",
tags: ["Board Member", "Next.js", "Tailwind CSS", "Prisma","TypeScript", "Web Development", "Automation"],
link: "https://datatjej.se",
sortOrder: 1
},
{
id: 5,
title: "DataTjej",
subtitle: "IT Support & User Management",
info: "As part of the DataTjej board, I manage user access and IT support for our growing community of over 6000 members. I handle user permissions, group management, and ensure secure access to our various platforms. This includes setting up and maintaining appropriate access levels for different user groups, troubleshooting technical issues, and implementing security best practices. I also work on automating user management processes and maintaining our IT infrastructure using Google Cloud services to support our community's needs.",
img: ["/images/datatjej-it-placeholder.jpg"],
previewImg: "/images/datatjej-it-placeholder.jpg",
tags: ["User Management", "IT Support", "Access Control", "Security", "Automation", "Community Management", "Google Cloud"],
link: "https://datatjej.se",
sortOrder: 4
}
]; ];
export const projectsAtom = atom({ key: "projects", default: experianceList }); // Sort the list by sortOrder
const sortedExperianceList = [...experianceList].sort((a, b) => a.sortOrder - b.sortOrder);
export const projectsAtom = atom({ key: "projects", default: sortedExperianceList });
export const skillsAtom = atom({ export const skillsAtom = atom({
key: "skills", key: "skills",
default: { default: {
@ -54,10 +85,11 @@ export const skillsAtom = atom({
"MySQL", "MySQL",
"Docker", "Docker",
"Visual Studio Code", "Visual Studio Code",
"Postman API", "Rapid API",
"TablePlus", "TablePlus",
"Trello", "Trello",
"Figma", "Figma",
"Blender",
], ],
}, },
}); });

View File

@ -3,9 +3,14 @@ export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: { theme: {
fontFamily: { fontFamily: {
sans: ["Ubuntu Mono", "system-ui"], //logo font
headline: ["Tektur", "system-ui"], logo: ["Sixtyfour", "system-ui"],
tags: ["Ubuntu Mono", "system-ui"], //headline-title text
ht: ["Sora", "system-ui"],
//body text
body: ["Jura", "system-ui"],
//nav
tags: ["Raleway", "system-ui"],
}, },
fontSize: { fontSize: {
title: ["5rem", { lineHeight: "5rem", fontWeight: "900" }], title: ["5rem", { lineHeight: "5rem", fontWeight: "900" }],
@ -16,7 +21,7 @@ export default {
subTMiniPhone: ["1.2rem", { lineHeight: "1.2rem", fontWeight: "800" }], subTMiniPhone: ["1.2rem", { lineHeight: "1.2rem", fontWeight: "800" }],
tags: ["0.8rem", { fontWeight: "400" }], tags: ["0.8rem", { fontWeight: "400" }],
sm: "0.8rem", sm: "0.8rem",
base: "1rem", base: "1.2rem",
xl: "1.25rem", xl: "1.25rem",
"2xl": "1.563rem", "2xl": "1.563rem",
"3xl": "1.953rem", "3xl": "1.953rem",
@ -25,20 +30,24 @@ export default {
}, },
extend: { extend: {
colors: { colors: {
neon: "#ccff00", neon: "#caebfa",
bgColor: "#031417", bgColor: "#F0F0F3",
highlight: "#ccff00", highlight: "#D2D2D2",
}, },
//20px 20px 60px #bebebe, -20px -20px 60px #ffffff;
boxShadow: {
box: "8px 8px 16px #cacaca,-8px -8px 16px #f6f6f6",
// box: "rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px, rgba(10, 37, 64, 0.35) 0px -2px 6px 0px inset;",
},
dropShadow: { dropShadow: {
light: "0 0 5px theme('colors.indigo.800')", light: "0 0 5px theme('colors.sky.100')",
yellow: "0 0 9px theme('colors.lime.400')", gray: "0 0 9px #8c92a8",
doublelight: [ doublelight: ["0 0 5px #96989a", "0 0 15px #a0d9fa"],
"0 0 5px theme('colors.lime.400')", //doublelight:
"0 0 15px theme('colors.yellow.400')",
],
active: [ active: [
"0 0 5px theme('colors.lime.400')", "0 0 5px theme('colors.sky.300')",
"0 0 15px theme('colors.indigo.950')", "0 0 15px theme('colors.sky.100')",
], ],
}, },
}, },