Implement 🥚

This commit is contained in:
grimsi
2024-09-27 11:04:13 +02:00
parent e47ab8405f
commit c8eaf0fb54
4 changed files with 102 additions and 23 deletions
+56
View File
@@ -44,6 +44,7 @@
"moment-timezone": "^0.5.45",
"next-themes": "^0.3.0",
"react": "18.3.1",
"react-confetti-boom": "^1.0.0",
"react-dom": "18.3.1",
"react-router-dom": "6.26.1",
"sonner": "^1.5.0",
@@ -1959,6 +1960,25 @@
"node": ">=6.9.0"
}
},
"node_modules/@emotion/is-prop-valid": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz",
"integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@emotion/memoize": "0.7.1"
}
},
"node_modules/@emotion/memoize": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz",
"integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==",
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -12213,6 +12233,19 @@
"node": ">=0.10.0"
}
},
"node_modules/react-confetti-boom": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-confetti-boom/-/react-confetti-boom-1.0.0.tgz",
"integrity": "sha512-JPCs1tx36xduFdMORaRLLvFJABAQUgjEqKvqZiBZr8bUkHsCzbHeesnfQwZU1LExmGiYVFGIJS/tiR4OUTktww==",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/react-dom": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
@@ -16299,6 +16332,23 @@
"to-fast-properties": "^2.0.0"
}
},
"@emotion/is-prop-valid": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz",
"integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==",
"optional": true,
"peer": true,
"requires": {
"@emotion/memoize": "0.7.1"
}
},
"@emotion/memoize": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz",
"integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==",
"optional": true,
"peer": true
},
"@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -23397,6 +23447,12 @@
"loose-envify": "^1.1.0"
}
},
"react-confetti-boom": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-confetti-boom/-/react-confetti-boom-1.0.0.tgz",
"integrity": "sha512-JPCs1tx36xduFdMORaRLLvFJABAQUgjEqKvqZiBZr8bUkHsCzbHeesnfQwZU1LExmGiYVFGIJS/tiR4OUTktww==",
"requires": {}
},
"react-dom": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+4 -2
View File
@@ -39,6 +39,7 @@
"moment-timezone": "^0.5.45",
"next-themes": "^0.3.0",
"react": "18.3.1",
"react-confetti-boom": "^1.0.0",
"react-dom": "18.3.1",
"react-router-dom": "6.26.1",
"sonner": "^1.5.0",
@@ -122,7 +123,8 @@
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles",
"cron-validator": "$cron-validator",
"moment": "$moment",
"moment-timezone": "$moment-timezone"
"moment-timezone": "$moment-timezone",
"react-confetti-boom": "$react-confetti-boom"
},
"vaadin": {
"dependencies": {
@@ -181,6 +183,6 @@
"workbox-core": "7.1.0",
"workbox-precaching": "7.1.0"
},
"hash": "9af3f915316df3b36e94b855108f7148a48217645c62f7b0e5a970f3030981b5"
"hash": "e5da4862f0edd6fde265ae72b8f5ec20ca6276687df8b437c1ebf9324053fb01"
}
}
+4 -8
View File
@@ -18,22 +18,18 @@ export default function LoginView() {
const [url, setUrl] = useState<string>();
const [signUpAllowed, setSignUpAllowed] = useState<boolean>(false);
useEffect(() => {
RegistrationEndpoint.isSelfRegistrationAllowed().then(setSignUpAllowed);
}, []);
useEffect(() => {
if (state.user) {
const path = url ? new URL(url, document.baseURI).pathname : '/'
navigate(path, {replace: true});
} else {
RegistrationEndpoint.isSelfRegistrationAllowed().then(setSignUpAllowed);
}
}, [state.user]);
async function tryLogin(values: any, formik: any) {
const {defaultUrl, error, redirectUrl} = await login(values.username, values.password);
if (!error) {
setUrl(redirectUrl ?? defaultUrl ?? '/');
} else {
const {error} = await login(values.username, values.password);
if (error) {
formik.setFieldError("username", " "); // Mark the field red, but don't show an error message
formik.setFieldError("password", "Invalid username and/or password.");
}
+38 -13
View File
@@ -1,24 +1,46 @@
import {useRouteMetadata} from 'Frontend/util/routing.js';
import {useEffect} from 'react';
import {useEffect, useState} from 'react';
import ProfileMenu from "Frontend/components/ProfileMenu";
import {Divider, Link, Navbar, NavbarBrand, NavbarContent, NavbarItem} from "@nextui-org/react";
import GameyfinLogo from "Frontend/components/theming/GameyfinLogo";
import * as PackageJson from "../../../../package.json";
import {Outlet, useNavigate} from "react-router-dom";
import {useAuth} from "Frontend/util/auth";
import {Heart} from "@phosphor-icons/react";
import Confetti, {ConfettiProps} from "react-confetti-boom";
export default function MainLayout() {
const navigate = useNavigate();
const auth = useAuth();
const routeMetadata = useRouteMetadata();
const [isExploding, setIsExploding] = useState(false);
useEffect(() => {
let newTitle = `Gameyfin - ${routeMetadata?.title}` ?? 'Gameyfin';
window.addEventListener('popstate', () => document.title = newTitle);
}, []);
const confettiProps: ConfettiProps = {
mode: 'boom',
x: 0.5,
y: 1,
particleCount: 1000,
spreadDeg: 90,
launchSpeed: 4,
effectInterval: 10000
}
function easterEgg() {
if (isExploding) return;
setIsExploding(true);
if (confettiProps.mode === "boom") {
setTimeout(() => setIsExploding(false), confettiProps.effectInterval);
}
}
return (
<div className="flex flex-col min-h-svh">
{isExploding ? <Confetti {...confettiProps}/> : <></>}
<div className="flex flex-col flex-grow w-full 2xl:w-3/4 m-auto">
<Navbar maxWidth="full">
<NavbarBrand as="button" onClick={() => navigate('/')}>
@@ -44,17 +66,20 @@ export default function MainLayout() {
</div>
<Divider/>
<footer className="flex flex-row items-center justify-between py-4 px-12">
<p>Gameyfin {PackageJson.version}</p>
<p>
&copy; {(new Date()).getFullYear()}&ensp;
<Link href="https://github.com/gameyfin/gameyfin/graphs/contributors" target="_blank">
Gameyfin contributors
</Link>
</p>
</footer>
<div className="flex flex-col w-full 2xl:w-3/4 m-auto">
<footer className="flex flex-row items-center justify-between py-4 px-12">
<p>Gameyfin {PackageJson.version}</p>
<p className="flex flex-row gap-1 items-baseline">
Made with
<Heart size={16} weight="fill" className="text-primary" onClick={easterEgg}/>
by
<Link href="https://github.com/grimsi" target="_blank">grimsi</Link> and
<Link href="https://github.com/gameyfin/gameyfin/graphs/contributors" target="_blank">
contributors
</Link>
</p>
</footer>
</div>
</div>
);
}
/**/
}