mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 16:20:04 +00:00
Implement 🥚
This commit is contained in:
Generated
+56
@@ -44,6 +44,7 @@
|
|||||||
"moment-timezone": "^0.5.45",
|
"moment-timezone": "^0.5.45",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
|
"react-confetti-boom": "^1.0.0",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-router-dom": "6.26.1",
|
"react-router-dom": "6.26.1",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.5.0",
|
||||||
@@ -1959,6 +1960,25 @@
|
|||||||
"node": ">=6.9.0"
|
"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": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||||
@@ -12213,6 +12233,19 @@
|
|||||||
"node": ">=0.10.0"
|
"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": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
@@ -16299,6 +16332,23 @@
|
|||||||
"to-fast-properties": "^2.0.0"
|
"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": {
|
"@esbuild/aix-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||||
@@ -23397,6 +23447,12 @@
|
|||||||
"loose-envify": "^1.1.0"
|
"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": {
|
"react-dom": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
|
|||||||
+4
-2
@@ -39,6 +39,7 @@
|
|||||||
"moment-timezone": "^0.5.45",
|
"moment-timezone": "^0.5.45",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
|
"react-confetti-boom": "^1.0.0",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-router-dom": "6.26.1",
|
"react-router-dom": "6.26.1",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.5.0",
|
||||||
@@ -122,7 +123,8 @@
|
|||||||
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles",
|
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles",
|
||||||
"cron-validator": "$cron-validator",
|
"cron-validator": "$cron-validator",
|
||||||
"moment": "$moment",
|
"moment": "$moment",
|
||||||
"moment-timezone": "$moment-timezone"
|
"moment-timezone": "$moment-timezone",
|
||||||
|
"react-confetti-boom": "$react-confetti-boom"
|
||||||
},
|
},
|
||||||
"vaadin": {
|
"vaadin": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -181,6 +183,6 @@
|
|||||||
"workbox-core": "7.1.0",
|
"workbox-core": "7.1.0",
|
||||||
"workbox-precaching": "7.1.0"
|
"workbox-precaching": "7.1.0"
|
||||||
},
|
},
|
||||||
"hash": "9af3f915316df3b36e94b855108f7148a48217645c62f7b0e5a970f3030981b5"
|
"hash": "e5da4862f0edd6fde265ae72b8f5ec20ca6276687df8b437c1ebf9324053fb01"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,22 +18,18 @@ export default function LoginView() {
|
|||||||
const [url, setUrl] = useState<string>();
|
const [url, setUrl] = useState<string>();
|
||||||
const [signUpAllowed, setSignUpAllowed] = useState<boolean>(false);
|
const [signUpAllowed, setSignUpAllowed] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
RegistrationEndpoint.isSelfRegistrationAllowed().then(setSignUpAllowed);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.user) {
|
if (state.user) {
|
||||||
const path = url ? new URL(url, document.baseURI).pathname : '/'
|
const path = url ? new URL(url, document.baseURI).pathname : '/'
|
||||||
navigate(path, {replace: true});
|
navigate(path, {replace: true});
|
||||||
|
} else {
|
||||||
|
RegistrationEndpoint.isSelfRegistrationAllowed().then(setSignUpAllowed);
|
||||||
}
|
}
|
||||||
}, [state.user]);
|
}, [state.user]);
|
||||||
|
|
||||||
async function tryLogin(values: any, formik: any) {
|
async function tryLogin(values: any, formik: any) {
|
||||||
const {defaultUrl, error, redirectUrl} = await login(values.username, values.password);
|
const {error} = await login(values.username, values.password);
|
||||||
if (!error) {
|
if (error) {
|
||||||
setUrl(redirectUrl ?? defaultUrl ?? '/');
|
|
||||||
} else {
|
|
||||||
formik.setFieldError("username", " "); // Mark the field red, but don't show an error message
|
formik.setFieldError("username", " "); // Mark the field red, but don't show an error message
|
||||||
formik.setFieldError("password", "Invalid username and/or password.");
|
formik.setFieldError("password", "Invalid username and/or password.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,46 @@
|
|||||||
import {useRouteMetadata} from 'Frontend/util/routing.js';
|
import {useRouteMetadata} from 'Frontend/util/routing.js';
|
||||||
import {useEffect} from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
import ProfileMenu from "Frontend/components/ProfileMenu";
|
import ProfileMenu from "Frontend/components/ProfileMenu";
|
||||||
import {Divider, Link, Navbar, NavbarBrand, NavbarContent, NavbarItem} from "@nextui-org/react";
|
import {Divider, Link, Navbar, NavbarBrand, NavbarContent, NavbarItem} from "@nextui-org/react";
|
||||||
import GameyfinLogo from "Frontend/components/theming/GameyfinLogo";
|
import GameyfinLogo from "Frontend/components/theming/GameyfinLogo";
|
||||||
import * as PackageJson from "../../../../package.json";
|
import * as PackageJson from "../../../../package.json";
|
||||||
import {Outlet, useNavigate} from "react-router-dom";
|
import {Outlet, useNavigate} from "react-router-dom";
|
||||||
import {useAuth} from "Frontend/util/auth";
|
import {useAuth} from "Frontend/util/auth";
|
||||||
|
import {Heart} from "@phosphor-icons/react";
|
||||||
|
import Confetti, {ConfettiProps} from "react-confetti-boom";
|
||||||
|
|
||||||
export default function MainLayout() {
|
export default function MainLayout() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
const routeMetadata = useRouteMetadata();
|
const routeMetadata = useRouteMetadata();
|
||||||
|
const [isExploding, setIsExploding] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let newTitle = `Gameyfin - ${routeMetadata?.title}` ?? 'Gameyfin';
|
let newTitle = `Gameyfin - ${routeMetadata?.title}` ?? 'Gameyfin';
|
||||||
window.addEventListener('popstate', () => document.title = newTitle);
|
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 (
|
return (
|
||||||
<div className="flex flex-col min-h-svh">
|
<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">
|
<div className="flex flex-col flex-grow w-full 2xl:w-3/4 m-auto">
|
||||||
<Navbar maxWidth="full">
|
<Navbar maxWidth="full">
|
||||||
<NavbarBrand as="button" onClick={() => navigate('/')}>
|
<NavbarBrand as="button" onClick={() => navigate('/')}>
|
||||||
@@ -44,17 +66,20 @@ export default function MainLayout() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<footer className="flex flex-row items-center justify-between py-4 px-12">
|
<div className="flex flex-col w-full 2xl:w-3/4 m-auto">
|
||||||
<p>Gameyfin {PackageJson.version}</p>
|
<footer className="flex flex-row items-center justify-between py-4 px-12">
|
||||||
<p>
|
<p>Gameyfin {PackageJson.version}</p>
|
||||||
© {(new Date()).getFullYear()} 
|
<p className="flex flex-row gap-1 items-baseline">
|
||||||
<Link href="https://github.com/gameyfin/gameyfin/graphs/contributors" target="_blank">
|
Made with
|
||||||
Gameyfin contributors
|
<Heart size={16} weight="fill" className="text-primary" onClick={easterEgg}/>
|
||||||
</Link>
|
by
|
||||||
</p>
|
<Link href="https://github.com/grimsi" target="_blank">grimsi</Link> and
|
||||||
</footer>
|
<Link href="https://github.com/gameyfin/gameyfin/graphs/contributors" target="_blank">
|
||||||
|
contributors
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
|
||||||
Reference in New Issue
Block a user