mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 08:15:48 +00:00
Refactored side-menu code
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="UI debug" type="JavascriptDebugType" engineId="37cae5b9-e8b2-4949-9172-aafa37fbc09c" uri="http://localhost:8080" useFirstLineBreakpoints="true">
|
<configuration default="false" name="UI debug" type="JavascriptDebugType" engineId="37cae5b9-e8b2-4949-9172-aafa37fbc09c" uri="http://localhost:8080">
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
Generated
+728
-724
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -4,7 +4,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-tailwind/react": "^2.1.9",
|
"@material-tailwind/react": "^2.1.9",
|
||||||
"@nextui-org/react": "^2.4.6",
|
"@nextui-org/react": "^2.4.8",
|
||||||
"@phosphor-icons/react": "^2.1.7",
|
"@phosphor-icons/react": "^2.1.7",
|
||||||
"@polymer/polymer": "3.5.1",
|
"@polymer/polymer": "3.5.1",
|
||||||
"@vaadin/bundles": "24.4.7",
|
"@vaadin/bundles": "24.4.7",
|
||||||
@@ -177,6 +177,6 @@
|
|||||||
"workbox-core": "7.1.0",
|
"workbox-core": "7.1.0",
|
||||||
"workbox-precaching": "7.1.0"
|
"workbox-precaching": "7.1.0"
|
||||||
},
|
},
|
||||||
"hash": "e4807cd1e75275abaaf1e41e23a8662d8fe4d7fb38029306089a3997a813d25e"
|
"hash": "0f5c2e2c0e435bad7d8e5153f11e7caac2a6024927de828fb8a6192acc6fd341"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Outlet, useNavigate} from 'react-router-dom';
|
import {Outlet, useHref, useNavigate} from 'react-router-dom';
|
||||||
import "./main.css";
|
import "./main.css";
|
||||||
import "Frontend/util/custom-validators";
|
import "Frontend/util/custom-validators";
|
||||||
import {NextUIProvider} from "@nextui-org/react";
|
import {NextUIProvider} from "@nextui-org/react";
|
||||||
@@ -16,7 +16,7 @@ export default function App() {
|
|||||||
client.middlewares = [ErrorHandlingMiddleware];
|
client.middlewares = [ErrorHandlingMiddleware];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NextUIProvider className="size-full" navigate={navigate}>
|
<NextUIProvider className="size-full" navigate={navigate} useHref={useHref}>
|
||||||
<NextThemesProvider attribute="class" themes={themeNames()} defaultTheme="gameyfin-violet-dark">
|
<NextThemesProvider attribute="class" themes={themeNames()} defaultTheme="gameyfin-violet-dark">
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<IconContext.Provider value={{size: 20}}>
|
<IconContext.Provider value={{size: 20}}>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export default function ProfileManagement() {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<Button
|
<Button
|
||||||
className="button-secondary"
|
color="primary"
|
||||||
isLoading={formik.isSubmitting}
|
isLoading={formik.isSubmitting}
|
||||||
disabled={formik.isSubmitting || configSaved}
|
disabled={formik.isSubmitting || configSaved}
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React from "react";
|
||||||
|
import withConfigPage from "Frontend/components/administration/withConfigPage";
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
|
function SsoMangementLayout({getConfig, formik}: any) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const validationSchema = Yup.object({});
|
||||||
|
|
||||||
|
export const SsoManagement = withConfigPage(SsoMangementLayout, "Single Sign-On", "sso", validationSchema);
|
||||||
@@ -134,7 +134,7 @@ export default function withConfigPage(WrappedComponent: React.ComponentType<any
|
|||||||
<h1 className="text-2xl font-bold">{title}</h1>
|
<h1 className="text-2xl font-bold">{title}</h1>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="button-secondary"
|
color="primary"
|
||||||
isLoading={formik.isSubmitting}
|
isLoading={formik.isSubmitting}
|
||||||
disabled={formik.isSubmitting || configSaved}
|
disabled={formik.isSubmitting || configSaved}
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import {Outlet} from "react-router-dom";
|
||||||
|
import {Icon} from "@phosphor-icons/react";
|
||||||
|
import {Listbox, ListboxItem} from "@nextui-org/react";
|
||||||
|
import {ReactElement, useState} from "react";
|
||||||
|
|
||||||
|
export type MenuItem = {
|
||||||
|
title: string,
|
||||||
|
url: string,
|
||||||
|
icon: ReactElement<Icon>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function withSideMenu(menuItems: MenuItem[]) {
|
||||||
|
return function PageWithSideMenu() {
|
||||||
|
const [selectedItem, setSelectedItem] = useState<string>(initialSelected)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a "/" at the start if it exists
|
||||||
|
*/
|
||||||
|
function key(k: string): string {
|
||||||
|
return k.replace(/^(\/)/, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the key starts with "/" assume it's an absolute link, else assume it's relative
|
||||||
|
*/
|
||||||
|
function link(l: string): string {
|
||||||
|
if (l.startsWith("/")) return l;
|
||||||
|
const p = window.location.pathname
|
||||||
|
return p.substring(0, p.lastIndexOf("/") + 1) + l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match the initially selected item by current URL path
|
||||||
|
*/
|
||||||
|
function initialSelected(): string {
|
||||||
|
const p = window.location.pathname
|
||||||
|
return p.substring(p.lastIndexOf("/") + 1, p.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<div className="flex flex-col pr-8">
|
||||||
|
<Listbox className="min-w-60"
|
||||||
|
color="primary">
|
||||||
|
{menuItems.map((i) => (
|
||||||
|
<ListboxItem key={key(i.url)} startContent={i.icon} href={link(i.url)}
|
||||||
|
onPress={() => setSelectedItem(i.url)}
|
||||||
|
className={`h-12 ${key(i.url) === selectedItem ? "bg-primary" : ""}`}>
|
||||||
|
<p>{i.title}</p>
|
||||||
|
</ListboxItem>
|
||||||
|
))}
|
||||||
|
</Listbox>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col flex-grow">
|
||||||
|
<Outlet/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,14 @@ import LoginView from "Frontend/views/LoginView";
|
|||||||
import MainLayout from "Frontend/views/MainLayout";
|
import MainLayout from "Frontend/views/MainLayout";
|
||||||
import TestView from "Frontend/views/TestView";
|
import TestView from "Frontend/views/TestView";
|
||||||
import SetupView from "Frontend/views/SetupView";
|
import SetupView from "Frontend/views/SetupView";
|
||||||
import ProfileView from "Frontend/views/ProfileView";
|
|
||||||
import {ThemeSelector} from "Frontend/components/theming/ThemeSelector";
|
import {ThemeSelector} from "Frontend/components/theming/ThemeSelector";
|
||||||
import App from "Frontend/App";
|
import App from "Frontend/App";
|
||||||
import AdministrationView from "Frontend/views/AdministrationView";
|
|
||||||
import {LibraryManagement} from "Frontend/components/administration/LibraryManagement";
|
import {LibraryManagement} from "Frontend/components/administration/LibraryManagement";
|
||||||
import {UserManagement} from "Frontend/components/administration/UserManagement";
|
import {UserManagement} from "Frontend/components/administration/UserManagement";
|
||||||
import ProfileManagement from "Frontend/components/administration/ProfileManagement";
|
import ProfileManagement from "Frontend/components/administration/ProfileManagement";
|
||||||
|
import {SsoManagement} from "Frontend/components/administration/SsoManagement";
|
||||||
|
import {AdministrationView} from "Frontend/views/AdministrationView";
|
||||||
|
import {ProfileView} from "Frontend/views/ProfileView";
|
||||||
|
|
||||||
export const routes = protectRoutes([
|
export const routes = protectRoutes([
|
||||||
{
|
{
|
||||||
@@ -38,6 +39,7 @@ export const routes = protectRoutes([
|
|||||||
children: [
|
children: [
|
||||||
{path: 'libraries', element: <LibraryManagement/>},
|
{path: 'libraries', element: <LibraryManagement/>},
|
||||||
{path: 'users', element: <UserManagement/>},
|
{path: 'users', element: <UserManagement/>},
|
||||||
|
{path: 'sso', element: <SsoManagement/>},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,45 +1,27 @@
|
|||||||
import {Outlet, useNavigate} from "react-router-dom";
|
import {Envelope, GameController, LockKey, Users} from "@phosphor-icons/react";
|
||||||
import {Envelope, GameController, Users} from "@phosphor-icons/react";
|
import withSideMenu, {MenuItem} from "Frontend/components/general/withSideMenu";
|
||||||
import {Listbox, ListboxItem} from "@nextui-org/react";
|
|
||||||
|
|
||||||
export default function AdministrationView() {
|
const menuItems: MenuItem[] = [
|
||||||
const navigate = useNavigate();
|
{
|
||||||
|
title: "Libraries",
|
||||||
|
url: "libraries",
|
||||||
|
icon: <GameController/>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Users",
|
||||||
|
url: "users",
|
||||||
|
icon: <Users/>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "SSO",
|
||||||
|
url: "sso",
|
||||||
|
icon: <LockKey/>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Notifications",
|
||||||
|
url: "notifications",
|
||||||
|
icon: <Envelope/>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
const menuItems = [
|
export const AdministrationView = withSideMenu(menuItems);
|
||||||
{
|
|
||||||
title: "Libraries",
|
|
||||||
key: "libraries",
|
|
||||||
icon: <GameController/>,
|
|
||||||
action: () => navigate('libraries')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Users",
|
|
||||||
key: "users",
|
|
||||||
icon: <Users/>,
|
|
||||||
action: () => navigate('users')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Notifications",
|
|
||||||
icon: <Envelope/>,
|
|
||||||
key: "notifications",
|
|
||||||
action: () => navigate('notifications')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-row">
|
|
||||||
<div className="flex flex-col pr-8">
|
|
||||||
<Listbox className="min-w-60">
|
|
||||||
{menuItems.map((i) => (
|
|
||||||
<ListboxItem key={i.key} onPress={i.action} startContent={i.icon}>
|
|
||||||
{i.title}
|
|
||||||
</ListboxItem>
|
|
||||||
))}
|
|
||||||
</Listbox>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col flex-grow">
|
|
||||||
<Outlet/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,45 +1,22 @@
|
|||||||
import {Listbox, ListboxItem} from "@nextui-org/react";
|
|
||||||
import {GearFine, Palette, User} from "@phosphor-icons/react";
|
import {GearFine, Palette, User} from "@phosphor-icons/react";
|
||||||
import {Outlet, useNavigate} from "react-router-dom";
|
import withSideMenu from "Frontend/components/general/withSideMenu";
|
||||||
|
|
||||||
export default function ProfileView() {
|
const menuItems = [
|
||||||
const navigate = useNavigate();
|
{
|
||||||
|
title: "My Profile",
|
||||||
|
url: "profile",
|
||||||
|
icon: <User/>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Appearance",
|
||||||
|
url: "appearance",
|
||||||
|
icon: <Palette/>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Manage account",
|
||||||
|
url: "account-management",
|
||||||
|
icon: <GearFine/>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
const menuItems = [
|
export const ProfileView = withSideMenu(menuItems);
|
||||||
{
|
|
||||||
title: "My Profile",
|
|
||||||
key: "profile",
|
|
||||||
icon: <User/>,
|
|
||||||
action: () => navigate('profile')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Appearance",
|
|
||||||
key: "appearance",
|
|
||||||
icon: <Palette/>,
|
|
||||||
action: () => navigate('appearance')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Manage account",
|
|
||||||
icon: <GearFine/>,
|
|
||||||
key: "account-management",
|
|
||||||
action: () => navigate('account-management')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-row">
|
|
||||||
<div className="flex flex-col pr-8">
|
|
||||||
<Listbox className="min-w-60">
|
|
||||||
{menuItems.map((i) => (
|
|
||||||
<ListboxItem key={i.key} onPress={i.action} startContent={i.icon}>
|
|
||||||
{i.title}
|
|
||||||
</ListboxItem>
|
|
||||||
))}
|
|
||||||
</Listbox>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col flex-grow">
|
|
||||||
<Outlet/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user