[#37] Login & Register Page UI https://project.mdnd-it.cc/work_packages/37 #3

Merged
Donat merged 2 commits from task/37-login-and-register-page-ui into main 2025-05-17 22:23:05 +02:00
18 changed files with 676 additions and 21 deletions
+103
View File
@@ -9,8 +9,10 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.7", "@tailwindcss/vite": "^4.1.7",
"framer-motion": "^12.12.1",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-router-dom": "^7.6.0",
"tailwindcss": "^4.1.7" "tailwindcss": "^4.1.7"
}, },
"devDependencies": { "devDependencies": {
@@ -2584,6 +2586,33 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/framer-motion": {
"version": "12.12.1",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.12.1.tgz",
"integrity": "sha512-PFw4/GCREHI2suK/NlPSUxd+x6Rkp80uQsfCRFSOQNrm5pZif7eGtmG1VaD/UF1fW9tRBy5AaS77StatB3OJDg==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.12.1",
"motion-utils": "^12.12.1",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fresh": { "node_modules/fresh": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
@@ -3344,6 +3373,21 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/motion-dom": {
"version": "12.12.1",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.12.1.tgz",
"integrity": "sha512-GXq/uUbZBEiFFE+K1Z/sxdPdadMdfJ/jmBALDfIuHGi0NmtealLOfH9FqT+6aNPgVx8ilq0DtYmyQlo6Uj9LKQ==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.12.1"
}
},
"node_modules/motion-utils": {
"version": "12.12.1",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.12.1.tgz",
"integrity": "sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w==",
"license": "MIT"
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -3705,6 +3749,53 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-router": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz",
"integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
"set-cookie-parser": "^2.6.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
},
"node_modules/react-router-dom": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.0.tgz",
"integrity": "sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==",
"license": "MIT",
"dependencies": {
"react-router": "7.6.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
},
"node_modules/react-router/node_modules/cookie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/resolve-from": { "node_modules/resolve-from": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -3854,6 +3945,12 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/set-cookie-parser": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
"license": "MIT"
},
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -4072,6 +4169,12 @@
"node": ">=0.6" "node": ">=0.6"
} }
}, },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+2
View File
@@ -11,8 +11,10 @@
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.7", "@tailwindcss/vite": "^4.1.7",
"framer-motion": "^12.12.1",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-router-dom": "^7.6.0",
"tailwindcss": "^4.1.7" "tailwindcss": "^4.1.7"
}, },
"devDependencies": { "devDependencies": {
View File
+41 -20
View File
@@ -1,26 +1,47 @@
import { useState } from 'react' import { useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import AuthRegister from "./pages/Auth/AuthRegister";
import AuthLogin from "./pages/Auth/AuthLogin";
import EmailVerification from "./pages/Auth/EmailVerification";
import Test from "./pages/Testing/Test";
function App() { function App() {
const [count, setCount] = useState(0) const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth <= 1280);
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
// if (isMobile) {
// return (
// <Router>
// <Routes>
// <Route path="/register" element={<AuthRegister />} />
// <Route path="/login" element={<AuthLogin />} />
// <Route path="/verify-email" element={<EmailVerification />} />
// </Routes>
// </Router>
// );
// }
return ( return (
<> <Router>
<div className="flex flex-col items-center bg-background justify-center min-h-screen"> <Routes>
<p className="text-text text-[60px]">primary</p> <Route path="/register" element={<AuthRegister />} />
<p className="text-text-muted text-[60px]">secondary</p> <Route path="/login" element={<AuthLogin />} />
<p className="text-accent text-[60px]">accent</p> <Route path="/verify-email" element={<EmailVerification />} />
<p className="text-background text-[60px]">background</p> <Route path="/test" element={<Test />} />
<p className="text-surface text-[60px]">surface</p> </Routes>
<p className="text-card text-[60px]">card</p> </Router>
<p className="text-text text-[60px]">text</p> );
<p className="text-text-muted text-[60px]">text-muted</p>
<p className="text-text-inverse text-[60px]">text-inverse</p>
<p className="text-success text-[60px]">success</p>
<p className="text-warning text-[60px]">warning</p>
<p className="text-error text-[60px]">error</p>
</div>
</>
)
} }
export default App export default App;
@@ -0,0 +1,95 @@
.animation {
animation: fill 0.5s ease forwards 2.9s;
}
.path0 {
stroke-dasharray: 603.0596923828125;
stroke-dashoffset: 603.0596923828125;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.45s;
}
.path1 {
stroke-dasharray: 503.0904846191406;
stroke-dashoffset: 503.0904846191406;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.5s;
}
.path2 {
stroke-dasharray: 625.779541015625;
stroke-dashoffset: 625.779541015625;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.45s;
}
.path3 {
stroke-dasharray: 714.129638671875;
stroke-dashoffset: 714.129638671875;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.4s;
}
.path4 {
stroke-dasharray: 427.98114013671875;
stroke-dashoffset: 427.98114013671875;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.35s;
}
.path5 {
stroke-dasharray: 593.7645263671875;
stroke-dashoffset: 593.7645263671875;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.3s;
}
.path6 {
stroke-dasharray: 603.0399780273438;
stroke-dashoffset: 603.0399780273438;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.25s;
}
.path7 {
stroke-dasharray: 731.757568359375;
stroke-dashoffset: 731.757568359375;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.2s;
}
.path8 {
stroke-dasharray: 382.3065185546875;
stroke-dashoffset: 382.3065185546875;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.2s;
}
.path9 {
stroke-dasharray: 603.0382690429688;
stroke-dashoffset: 603.0382690429688;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.15s;
}
.path10 {
stroke-dasharray: 652.2447509765625;
stroke-dashoffset: 652.2447509765625;
animation: draw 3s ease-in-out forwards;
animation-delay: 0.1s;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
@keyframes fill {
from {
fill: transparent;
}
to {
fill: #ffffff;
}
}
@@ -0,0 +1,31 @@
import styles from "./Path.module.css";
import React, { useRef } from "react";
const Animation = ({ sizePercentage = 100 }) => {
const width = (1253 * sizePercentage) / 100;
const height = (136 * sizePercentage) / 100;
// 11 path-hoz refs
const pathRefs = Array.from({ length: 11 }, () => useRef(null));
return (
<div>
{/* prettier-ignore */}
<svg className={styles.animation} width={width} height={height} viewBox="0 0 1319 198" fill="none" xmlns="http://www.w3.org/2000/svg">
<path ref={pathRefs[0]} className={styles.path0} d="M1261.64 32.9C1272.02 32.9 1281.15 34.9576 1289.1 39.0094L1289.86 39.4078C1297.97 43.7136 1304.29 49.9037 1308.86 58.026L1308.86 58.0328L1308.87 58.0406C1313.41 65.9983 1315.74 75.4878 1315.74 86.6002C1315.74 88.8329 1315.63 91.0662 1315.41 93.3004H1240.77L1240.94 95.9625C1241.36 102.425 1243.14 107.682 1246.63 111.328L1246.67 111.368L1246.71 111.407C1250.29 114.831 1254.8 116.5 1260.04 116.5C1263.69 116.5 1266.97 115.677 1269.77 113.917C1272.15 112.419 1274.06 110.315 1275.55 107.7H1312.61C1310.88 113.608 1308.06 118.989 1304.16 123.859L1303.71 124.408L1303.71 124.413C1299.18 129.919 1293.45 134.322 1286.48 137.611L1285.8 137.925C1278.56 141.229 1270.51 142.9 1261.64 142.9C1250.94 142.9 1241.49 140.648 1233.23 136.205C1225.37 131.905 1219.12 125.83 1214.46 117.933L1214.01 117.164C1209.46 108.936 1207.14 99.1765 1207.14 87.8004C1207.14 76.4113 1209.46 66.7169 1214.01 58.6256L1214.02 58.6187L1214.02 58.6109C1218.45 50.6085 1224.53 44.4249 1232.28 40.0143L1233.04 39.5934C1241.29 35.1536 1250.8 32.9 1261.64 32.9ZM1261.44 58.9C1256.17 58.9 1251.64 60.3691 1248.04 63.4723C1244.4 66.4788 1242.18 70.8761 1241.18 76.3473L1240.63 79.3004H1280.74V76.8004C1280.74 71.5541 1279.01 67.178 1275.39 63.985L1275.04 63.6793C1271.33 60.4557 1266.74 58.9 1261.44 58.9Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[1]} className={styles.path1} d="M1139.95 32.9C1153.73 32.9 1165.15 36.6867 1174.38 44.1441L1174.39 44.151L1174.4 44.1578C1182.91 50.9203 1188.68 60.2478 1191.63 72.3004H1154.9C1153.61 69.0944 1151.8 66.4744 1149.4 64.5846C1146.55 62.349 1143.08 61.3004 1139.15 61.3004C1133.38 61.3004 1128.7 63.7808 1125.31 68.5533L1125.31 68.5602L1125.3 68.566C1122.08 73.1723 1120.65 79.708 1120.65 87.8004C1120.65 95.9013 1122.08 102.479 1125.28 107.202L1125.31 107.247C1128.7 112.019 1133.38 114.5 1139.15 114.5C1143.13 114.5 1146.64 113.458 1149.5 111.215C1151.9 109.324 1153.68 106.702 1154.93 103.5H1191.63C1188.77 115.027 1183.29 124.135 1175.24 130.949L1174.38 131.656C1165.15 139.113 1153.73 142.9 1139.95 142.9C1129.25 142.9 1119.8 140.648 1111.55 136.205C1103.69 131.908 1097.51 125.841 1092.97 117.958L1092.54 117.189C1087.98 108.956 1085.65 99.188 1085.65 87.8004C1085.65 76.9027 1087.83 67.4559 1092.12 59.3873L1092.54 58.6109C1096.97 50.6085 1103.05 44.4249 1110.8 40.0143L1111.55 39.5934C1119.81 35.1513 1129.25 32.9 1139.95 32.9Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[2]} className={styles.path2} d="M995.014 32.9C1002.18 32.9 1008.26 34.2763 1013.33 36.9322L1013.81 37.193C1019.04 40.0563 1023.04 43.8802 1025.86 48.6695L1030.51 56.5602V34.3004H1064.71V141.5H1030.51V119.24L1025.86 127.13C1023.04 131.905 1019 135.728 1013.63 138.595L1013.61 138.607C1008.45 141.437 1002.27 142.9 995.014 142.9C986.807 142.9 979.357 140.83 972.608 136.697L971.956 136.291C965.401 132.037 960.089 125.994 956.045 118.069L955.657 117.296C951.72 108.895 949.714 99.0842 949.714 87.8004C949.714 76.5091 951.722 66.7655 955.656 58.5035L955.657 58.5045C959.747 50.1977 965.189 43.9003 971.956 39.5094C978.877 35.1054 986.542 32.9 995.014 32.9ZM1007.61 62.1002C1001.29 62.1002 995.894 64.2893 991.601 68.6617L991.217 69.0621C986.771 73.6617 984.714 80.0315 984.714 87.8004C984.714 95.4589 986.781 101.845 991.161 106.678L991.175 106.694L991.189 106.708C995.547 111.367 1001.08 113.7 1007.61 113.7C1014.02 113.7 1019.47 111.363 1023.81 106.738L1023.81 106.739C1028.38 102.021 1030.51 95.5962 1030.51 87.8004C1030.51 80.1231 1028.37 73.771 1023.81 69.0611H1023.81C1019.47 64.436 1014.01 62.1003 1007.61 62.1002Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[3]} className={styles.path3} d="M883.187 5.5C894.235 5.5 903.424 7.45044 910.854 11.2285L910.87 11.2363L910.885 11.2432C918.35 14.9128 923.893 19.9862 927.622 26.4492L927.628 26.458L927.633 26.4678C931.388 32.8524 933.288 40.075 933.288 48.2002C933.288 57.0202 930.924 64.7518 926.227 71.4814L925.765 72.1299L925.761 72.1367C920.94 78.8118 913.776 83.668 904.063 86.6074L901.045 87.5205L902.623 90.251L932.255 141.5H894.281L866.989 90.8145L866.281 89.5H858.088V141.5H823.888V5.5H883.187ZM858.088 67.7002H879.987C885.497 67.7002 890.109 66.4347 893.395 63.502L893.71 63.2129C897.012 60.0753 898.487 55.6661 898.487 50.4004C898.487 45.3401 896.908 41.0909 893.515 37.9932C890.228 34.7309 885.571 33.2998 879.987 33.2998H858.088V67.7002Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[4]} className={styles.path4} d="M780.308 7.09998V34.3002H800.707V61.8998H780.308V102C780.308 105.333 781.017 108.344 783.04 110.368L783.082 110.41L783.126 110.45C785.279 112.407 788.447 113.1 792.008 113.1H800.908V141.5H786.408C772.454 141.5 762.449 138.044 755.917 131.574C749.39 125.107 745.908 115.208 745.908 101.4V61.8998H732.108V34.3002H745.908V7.09998H780.308Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[5]} className={styles.path5} d="M673.499 33.3C685.81 33.3001 695.355 37.3928 702.419 45.4484L702.426 45.4553L702.431 45.4631C709.518 53.4205 713.198 64.3676 713.198 78.5998V141.5H678.999V83.8C678.999 77.1809 677.321 71.6461 673.69 67.4982L673.333 67.1017C669.469 62.7934 664.3 60.7004 658.098 60.7004C651.671 60.7004 646.352 62.7672 642.464 67.1017C638.585 71.2907 636.799 76.9677 636.799 83.8V141.5H602.598V34.3H636.799V55.881L641.362 49.2121C644.58 44.5096 648.924 40.7078 654.457 37.8156L654.476 37.8049L654.496 37.7951C659.947 34.8215 666.259 33.3 673.499 33.3Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[6]} className={styles.path6} d="M527.456 32.9C537.839 32.9 546.973 34.9576 554.918 39.0094L555.684 39.4078C563.789 43.7136 570.108 49.9038 574.677 58.026L574.682 58.0328L574.686 58.0406C579.233 65.9983 581.556 75.4878 581.556 86.6002C581.556 88.8329 581.446 91.0662 581.226 93.3004H506.588L506.762 95.9625C507.183 102.425 508.962 107.682 512.449 111.328L512.488 111.368L512.529 111.407C516.109 114.831 520.616 116.5 525.857 116.5C529.506 116.5 532.787 115.677 535.587 113.917C537.97 112.419 539.884 110.315 541.368 107.7H578.43C576.699 113.608 573.884 118.989 569.976 123.859L569.529 124.408L569.526 124.413C564.998 129.919 559.27 134.322 552.297 137.611L551.618 137.925C544.376 141.229 536.335 142.9 527.456 142.9C516.756 142.9 507.308 140.648 499.052 136.205C491.192 131.905 484.94 125.83 480.276 117.933L479.829 117.164C475.279 108.936 472.956 99.1765 472.956 87.8004C472.956 76.4113 475.284 66.7169 479.835 58.6256L479.839 58.6187L479.843 58.6109C484.415 50.3552 490.739 44.0358 498.842 39.6012C507.097 35.1564 516.612 32.9 527.456 32.9ZM527.256 58.9C521.992 58.9 517.458 60.3691 513.864 63.4723C510.225 66.4788 508.005 70.8761 506.997 76.3473L506.453 79.3004H546.556V76.8004C546.556 71.5541 544.83 67.178 541.213 63.985L540.857 63.6793C537.15 60.4557 532.556 58.9 527.256 58.9Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[7]} className={styles.path7} d="M412.919 32.9C421.39 32.9 428.981 35.1048 435.759 39.4977L435.776 39.5094C442.673 43.8984 448.109 50.187 452.062 58.4762L452.069 58.4898L452.076 58.5045C456.143 66.7653 458.219 76.5074 458.219 87.8004C458.219 99.0921 456.143 108.907 452.069 117.309L452.065 117.317L452.062 117.324C448.109 125.613 442.673 131.902 435.776 136.291L435.759 136.302C428.981 140.695 421.39 142.9 412.919 142.9C405.885 142.9 399.874 141.527 394.806 138.869L394.319 138.607C389.224 135.744 385.214 131.91 382.248 127.089L377.619 119.567V195.1H343.419V34.3004H377.619V56.5602L382.272 48.6695C385.009 44.0298 388.842 40.2965 393.833 37.4644L394.319 37.193C399.487 34.363 405.659 32.9 412.919 32.9ZM400.518 62.1002C394.105 62.1003 388.591 64.443 384.122 69.0611L384.107 69.0768L384.094 69.0924C379.685 73.8051 377.619 80.1455 377.619 87.8004C377.619 95.5741 379.677 101.987 384.094 106.708L384.107 106.723L384.122 106.739C388.591 111.357 394.105 113.7 400.518 113.7C406.933 113.7 412.396 111.354 416.742 106.709L416.743 106.71C421.272 101.878 423.419 95.4809 423.419 87.8004C423.419 80.2525 421.414 74.0286 417.11 69.4684L416.686 69.0318C412.349 64.4263 406.905 62.1002 400.518 62.1002Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[8]} className={styles.path8} d="M324.366 70.0998H315.866C307.359 70.0998 300.513 71.6968 295.751 75.299L295.297 75.6535C290.309 79.6756 288.166 86.4018 288.166 95.0002V141.5H253.966V34.3H288.166V59.6496L292.725 53.0168C296.934 46.8945 302.008 42.0849 307.945 38.548C313.097 35.4789 318.561 33.7613 324.366 33.381V70.0998Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[9]} className={styles.path9} d="M178.823 32.9C189.206 32.9 198.34 34.9576 206.285 39.0094L207.051 39.4078C215.156 43.7136 221.475 49.9038 226.044 58.026L226.049 58.0328L226.053 58.0406C230.6 65.9983 232.923 75.4878 232.923 86.6002C232.923 88.8329 232.813 91.0662 232.593 93.3004H157.955L158.129 95.9625C158.551 102.425 160.329 107.682 163.817 111.328L163.856 111.368L163.896 111.407C167.476 114.831 171.984 116.5 177.224 116.5C180.873 116.5 184.154 115.677 186.954 113.917C189.337 112.419 191.252 110.315 192.736 107.7H229.797C228.066 113.608 225.251 118.989 221.343 123.859L220.896 124.408L220.893 124.413C216.365 129.919 210.637 134.322 203.664 137.611L202.986 137.925C195.743 141.229 187.702 142.9 178.823 142.9C168.123 142.9 158.676 140.648 150.419 136.205C142.559 131.905 136.307 125.83 131.643 117.933L131.196 117.164C126.646 108.936 124.323 99.1765 124.323 87.8004C124.323 76.4113 126.651 66.7169 131.202 58.6256L131.206 58.6187L131.21 58.6109C135.642 50.6085 141.719 44.425 149.468 40.0143L150.223 39.5934C158.474 35.1535 167.986 32.9 178.823 32.9ZM178.623 58.9C173.359 58.9 168.825 60.3691 165.232 63.4723C161.592 66.4788 159.372 70.8761 158.364 76.3473L157.821 79.3004H197.923V76.8004C197.923 71.5541 196.198 67.178 192.58 63.985L192.224 63.6793C188.517 60.4557 183.924 58.9 178.623 58.9Z" stroke="white" strokeWidth="5"/>
<path ref={pathRefs[10]} className={styles.path10} d="M53.2002 3.29999C69.2163 3.30002 81.6771 7.07376 90.8447 14.3576L90.8594 14.3693L90.874 14.3801C99.4701 21.0014 104.378 30.1606 105.515 42.0998H67.8926C67.3698 38.4388 65.8881 35.3672 63.2598 33.131H63.2607C60.3137 30.5116 56.5476 29.3 52.2002 29.3C48.8465 29.3 45.8881 30.2761 43.5254 32.3625L43.2988 32.5676C40.7984 34.8894 39.7002 38.0949 39.7002 41.8C39.7002 45.173 40.9953 48.1303 43.4326 50.5676L43.4912 50.6262L43.5537 50.6818C45.8882 52.7245 48.6886 54.509 51.9209 56.0549L51.9619 56.0744L52.0029 56.093C55.1495 57.461 59.7476 59.217 65.7627 61.3557L65.7754 61.3605L65.7881 61.3644C74.6461 64.4053 81.8453 67.4222 87.4209 70.4045L87.4512 70.4211L87.4824 70.4357C92.9892 73.1892 97.6936 77.1341 101.605 82.3078L101.627 82.3351L101.647 82.3615C105.489 87.1639 107.5 93.3779 107.5 101.2C107.5 109.153 105.487 116.213 101.494 122.452L101.484 122.467L101.476 122.483C97.6244 128.694 91.9433 133.66 84.3125 137.349L84.2969 137.357C76.8439 141.02 67.9047 142.9 57.4004 142.9C41.8954 142.9 29.2947 139.363 19.4258 132.463L18.4795 131.784C9.25313 124.887 3.96894 115.274 2.70117 102.7H39.5801C40.2265 106.786 41.7043 110.177 44.2383 112.591L44.5332 112.863C47.604 115.611 51.5002 116.9 56 116.9C60.0031 116.9 63.5126 115.932 66.3184 113.786L66.3271 113.779L66.335 113.774C69.38 111.405 70.9003 108.125 70.9004 104.2C70.9004 99.2522 68.5707 95.3626 64.2852 92.6974L63.8643 92.4435C59.755 90.0347 53.2798 87.4365 44.5898 84.6281H44.5908C35.4593 81.5843 28.1131 78.6936 22.5186 75.9631C17.2902 73.2164 12.6467 69.2763 8.59375 64.091C4.86911 59.0319 2.90039 52.3374 2.90039 43.8C2.90039 35.1675 5.05101 27.9593 9.24023 22.0451L9.25391 22.0256C13.3581 16.1108 18.996 11.5666 26.2539 8.40936L26.9619 8.1076C34.6101 4.92092 43.342 3.29999 53.2002 3.29999Z" stroke="white" strokeWidth="5"/>
</svg>
</div>
);
};
export default Animation;
+102
View File
@@ -0,0 +1,102 @@
import React, { useEffect, useState } from "react";
import { motion } from "framer-motion";
const Background = () => {
const [gridSize, setGridSize] = useState({ cols: 12, rows: 6 });
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
const [path, setPath] = useState([]);
useEffect(() => {
const updateGrid = () => {
const width = window.innerWidth;
const height = window.innerHeight;
const cols = Math.max(8, Math.floor(width / 100)); // 100px-es cellák
const rows = Math.max(5, Math.floor(height / 100)); // 100px-es cellák
setGridSize({ cols, rows });
};
const handleMouseMove = (e) => {
setMousePos({ x: e.clientX, y: e.clientY });
};
updateGrid();
window.addEventListener("resize", updateGrid);
window.addEventListener("mousemove", handleMouseMove);
return () => {
window.removeEventListener("resize", updateGrid);
window.removeEventListener("mousemove", handleMouseMove);
};
}, []);
useEffect(() => {
const interval = setInterval(() => {
const newCol = Math.floor(Math.random() * gridSize.cols);
const newRow = Math.floor(Math.random() * gridSize.rows);
setPath((prevPath) => {
const newPath = [...prevPath, { col: newCol, row: newRow, opacity: 1 }]; // Új pont hozzáadása
if (newPath.length > 10) {
newPath.shift(); // Max 10 pont az útvonalon
}
return newPath;
});
}, 500); // Új pont hozzáadása minden 500ms-ben
// Az útvonal pontjainak fokozatos eltűnése
const fadeInterval = setInterval(() => {
setPath((prevPath) =>
prevPath.map((point) => ({
...point,
opacity: Math.max(0, point.opacity - 0.05), // Fokozatosan csökkentjük az opacity-t
})).filter((point) => point.opacity > 0) // Eltávolítjuk a teljesen eltűnt pontokat
);
}, 100); // Opacity frissítése minden 100ms-ben
return () => {
clearInterval(interval);
clearInterval(fadeInterval);
};
}, [gridSize]);
return (
<div className="relative w-full h-screen bg-background flex items-center justify-center overflow-hidden">
<div
className="absolute inset-0 grid gap-2 opacity-20"
style={{
gridTemplateColumns: `repeat(${gridSize.cols}, 1fr)`,
gridTemplateRows: `repeat(${gridSize.rows}, 1fr)`,
}}
>
{[...Array(gridSize.cols * gridSize.rows)].map((_, i) => {
const col = i % gridSize.cols;
const row = Math.floor(i / gridSize.cols);
const cellX = (col + 0.5) * (window.innerWidth / gridSize.cols);
const cellY = (row + 0.5) * (window.innerHeight / gridSize.rows);
const dx = cellX - mousePos.x;
const dy = cellY - mousePos.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const distanceFactor = Math.max(0, 1 - distance / 300); // Egér hatótávolsága
// Az útvonalban lévő pontok opacitása
const pathPoint = path.find((p) => p.col === col && p.row === row);
const pathOpacity = pathPoint ? pathPoint.opacity : 0;
return (
<motion.div
key={i}
className="w-full h-full bg-white rounded-lg"
animate={{
opacity: 0.05 + distanceFactor * 0.2 + pathOpacity * 0.5, // Kombinált opacitás
scale: 1 + distanceFactor * 0.05 + pathOpacity * 0.1, // Kombinált skálázás
}}
transition={{ duration: 0.5, ease: "easeOut" }} // Lassú és sima átmenet
/>
);
})}
</div>
</div>
);
};
export default Background;
@@ -0,0 +1,15 @@
import React from 'react';
import logo from './Logo.png';
const Logo = ({ size = 100 }) => (
<img
src={logo}
alt="Logo"
width={size}
height={size}
style={{ objectFit: 'contain' }}
/>
);
export default Logo;
Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

+18
View File
@@ -0,0 +1,18 @@
// src/components/Inputs/InputBox.jsx
// Gomb komponens
import { motion } from "framer-motion";
export default function Button({ text, type, onClick }) {
return (
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
type={type}
onClick={onClick}
className="w-full bg-button-primary text-white py-3 rounded-lg hover:bg-button-hover transition shadow-md font-semibold text-lg"
>
{text}
</motion.button>
);
}
+16
View File
@@ -0,0 +1,16 @@
// src/components/Inputs/InputBox.jsx
// InputBox komponens
export default function InputBox({ type, placeholder, value, onChange }) {
return (
<div className="mb-6 relative">
<input
type={type}
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:border-background focus:outline-none text-gray-700 placeholder-gray-400 bg-gray-50"
placeholder={placeholder}
value={value}
onChange={onChange}
/>
</div>
);
}
+8 -1
View File
@@ -3,11 +3,18 @@
@theme { @theme {
/* Fő színek */ /* Fő színek */
--color-night: #0d0d0f; --color-night: #0d0d0f;
--color-mint: #5fa985;
--color-battleship-gray: #8d8e83; --color-battleship-gray: #8d8e83;
--color-gunmetal: #222d2f; --color-gunmetal: #222d2f;
--color-eerie-black: #181d23; --color-eerie-black: #181d23;
--color-mint: #5fa985;
--color-mint-dark: #1e3328;
--color-mint-darker: #0f2019;
/* Gombok */
--color-button-primary: #5fa985;
--color-button-hover: #4b7e65;
/* Funkcionális színek */ /* Funkcionális színek */
--color-primary: #5fa985; --color-primary: #5fa985;
--color-secondary: #8d8e83; --color-secondary: #8d8e83;
+46
View File
@@ -0,0 +1,46 @@
// src/pages/Auth/AuthLogin.jsx
// Kártya amelyiken a bejelentkezés és regisztráció van
import { motion, AnimatePresence } from "framer-motion";
import Animation from "../../assets/SerpentRace_Animation/SerpentRace_Animation";
import LoginForm from "./LoginForm";
import RegisterForm from "./RegisterForm";
import Logo from "../../assets/pictures/Logo";
export default function AuthCard({ isRegistering, setIsRegistering }) {
return (
<motion.div
initial={{ height: "auto" }}
animate={{ height: isRegistering ? "600px" : "385px" }}
transition={{ duration: 0.5, ease: "easeInOut" }}
className="absolute flex max-w-4xl w-full bg-white rounded-2xl shadow-lg overflow-hidden"
>
{/* Bal oldali kép és szöveg */}
<div
className={`transition-all duration-500 ${isRegistering ? 'w-0 p-0' : 'w-2/5 p-8'} flex flex-col justify-center items-center bg-gradient-to-r from-mint-darker to-mint text-white `}
>
<Logo size={100}/>
<div className="h-6" />
<Animation sizePercentage={30} />
<p className="text-lg mt-0 text-center font-light whitespace-nowrap overflow-hidden">
Lépj be és légy a legjobb!
</p>
</div>
{/* Jobb oldali űrlap */}
<div className="w-full p-10 relative">
<AnimatePresence mode="wait">
{isRegistering ? <RegisterForm /> : <LoginForm />}
</AnimatePresence>
<span
className="text-secondary cursor-pointer hover:underline mt-4 block text-center"
onClick={() => setIsRegistering(!isRegistering)}
>
{isRegistering
? "Már van fiókod? Jelentkezz be itt!"
: "Nincs még fiókod? Regisztrálj itt!"}
</span>
</div>
</motion.div>
);
}
+18
View File
@@ -0,0 +1,18 @@
// src/pages/Auth/AuthLogin.jsx
// Login url címre érkezés (registering = false)
import { useState } from "react";
import Background from "../../assets/backgrounds/Background";
import AuthCard from "./AuthCard";
export default function AuthLogin() {
const [isRegistering, setIsRegistering] = useState(false);
return (
<div className="relative flex items-center justify-center min-h-screen bg-gray-100 p-0 font-poppins">
<Background />
<AuthCard isRegistering={isRegistering} setIsRegistering={setIsRegistering} />
</div>
);
}
+17
View File
@@ -0,0 +1,17 @@
// src/pages/Auth/AuthRegister.jsx
// Register url címre érkezés (registering = true)
import { useState } from "react";
import Background from "../../assets/backgrounds/Background";
import AuthCard from "./AuthCard";
export default function AuthRegister() {
const [isRegistering, setIsRegistering] = useState(true);
return (
<div className="relative flex items-center justify-center min-h-screen bg-gray-100 p-0 font-poppins">
<Background />
<AuthCard isRegistering={isRegistering} setIsRegistering={setIsRegistering} />
</div>
);
}
+62
View File
@@ -0,0 +1,62 @@
// src/pages/Auth/LoginForm.jsx
// Bejelentkezési űrlap
import InputBox from "../../components/Inputs/InputBox";
import Button from "../../components/Buttons/Button";
import { motion } from "framer-motion";
import { useState } from "react";
export default function LoginForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
function validateEmail(email) {
return /\S+@\S+\.\S+/.test(email);
}
const handleSubmit = (e) => {
e.preventDefault();
setError("");
if (!email || !password) {
setError("Minden mező kitöltése kötelező.");
return;
}
if (!validateEmail(email)) {
setError("Hibás email formátum.");
return;
}
// Backend API
console.log("Bejelentkezés:", { email, password });
};
return (
<motion.div
key="login"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.25 }}
>
<h2 className="text-4xl font-extrabold text-center mb-6 text-gray-800 tracking-wide">Bejelentkezés</h2>
{error && (
<div className="mb-4 text-red-600 text-center font-semibold">{error}</div>
)}
<form onSubmit={handleSubmit}>
<InputBox
type="email"
placeholder="Email cím"
value={email}
onChange={e => setEmail(e.target.value)}
/>
<InputBox
type="password"
placeholder="Jelszó"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<Button text="Bejelentkezés" type="submit" />
</form>
</motion.div>
);
}
+92
View File
@@ -0,0 +1,92 @@
// src/pages/Auth/RegisterForm.jsx
// Regisztrációs űrlap
import InputBox from "../../components/Inputs/InputBox";
import Button from "../../components/Buttons/Button";
import { motion } from "framer-motion";
import { useState } from "react";
export default function RegisterForm() {
const [fullName, setFullName] = useState("");
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [error, setError] = useState("");
function validateEmail(email) {
return /\S+@\S+\.\S+/.test(email);
}
const handleSubmit = (e) => {
e.preventDefault();
setError("");
if (!fullName || !username || !email || !password || !confirmPassword) {
setError("Minden mező kitöltése kötelező.");
return;
}
if (!validateEmail(email)) {
setError("Hibás email formátum.");
return;
}
if (password.length < 6) {
setError("A jelszónak legalább 6 karakter hosszúnak kell lennie.");
return;
}
if (password !== confirmPassword) {
setError("A jelszavak nem egyeznek.");
return;
}
// Backend API
console.log("Regisztráció:", { fullName, username, email, password });
};
return (
<motion.div
key="register"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.25 }}
>
<h2 className="text-4xl font-extrabold text-center mb-6 text-gray-800 tracking-wide">Regisztráció</h2>
{error && (
<div className="mb-4 text-red-600 text-center font-semibold">{error}</div>
)}
<form onSubmit={handleSubmit}>
<InputBox
type="text"
placeholder="Teljes név"
value={fullName}
onChange={e => setFullName(e.target.value)}
/>
<InputBox
type="text"
placeholder="Felhasználónév"
value={username}
onChange={e => setUsername(e.target.value)}
/>
<InputBox
type="email"
placeholder="Email cím"
value={email}
onChange={e => setEmail(e.target.value)}
/>
<InputBox
type="password"
placeholder="Jelszó"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<InputBox
type="password"
placeholder="Jelszó megerősítése"
value={confirmPassword}
onChange={e => setConfirmPassword(e.target.value)}
/>
<Button text="Regisztráció" type="submit" />
</form>
</motion.div>
);
}
@@ -0,0 +1,10 @@
import { useState } from "react";
export default function Test() {
return (
<div className="bg-red-100 text-white p-4">
<p className="text-piros">asd</p>
</div>
);
}