diff --git a/src/RootApp.tsx b/src/RootApp.tsx
index 62223f7236..0d66c15ad2 100644
--- a/src/RootApp.tsx
+++ b/src/RootApp.tsx
@@ -1,37 +1,53 @@
import loadable from '@loadable/component';
+import { ThemeProvider } from '@mui/material/styles';
import { History } from '@remix-run/router';
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
-import StableApp from './apps/stable/App';
-import { HistoryRouter } from './components/router/HistoryRouter';
-import { ApiProvider } from './hooks/useApi';
-import { WebConfigProvider } from './hooks/useWebConfig';
+import AppHeader from 'components/AppHeader';
+import Backdrop from 'components/Backdrop';
+import { HistoryRouter } from 'components/router/HistoryRouter';
+import { ApiProvider } from 'hooks/useApi';
+import { WebConfigProvider } from 'hooks/useWebConfig';
+import theme from 'themes/theme';
const ExperimentalApp = loadable(() => import('./apps/experimental/App'));
+const StableApp = loadable(() => import('./apps/stable/App'));
const queryClient = new QueryClient();
-const RootApp = ({ history }: { history: History }) => {
+const RootAppLayout = () => {
const layoutMode = localStorage.getItem('layout');
+ const isExperimentalLayout = layoutMode === 'experimental';
return (
-
-
-
-
- {
- layoutMode === 'experimental' ?
- :
-
- }
-
-
-
-
-
+ <>
+
+
+
+ {
+ isExperimentalLayout ?
+ :
+
+ }
+ >
);
};
+const RootApp = ({ history }: { history: History }) => (
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
export default RootApp;
diff --git a/src/apps/experimental/App.tsx b/src/apps/experimental/App.tsx
index 57ad22eae7..44c6d24b2d 100644
--- a/src/apps/experimental/App.tsx
+++ b/src/apps/experimental/App.tsx
@@ -1,16 +1,16 @@
import React from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
+import { REDIRECTS } from 'apps/stable/routes/_redirects';
import ConnectionRequired from 'components/ConnectionRequired';
import ServerContentPage from 'components/ServerContentPage';
import { toAsyncPageRoute } from 'components/router/AsyncRoute';
import { toViewManagerPageRoute } from 'components/router/LegacyRoute';
+import { toRedirectRoute } from 'components/router/Redirect';
import AppLayout from './AppLayout';
import { ASYNC_ADMIN_ROUTES, ASYNC_USER_ROUTES } from './routes/asyncRoutes';
import { LEGACY_ADMIN_ROUTES, LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES } from './routes/legacyRoutes';
-import { REDIRECTS } from 'apps/stable/routes/_redirects';
-import { toRedirectRoute } from 'components/router/Redirect';
const ExperimentalApp = () => {
return (
@@ -38,10 +38,10 @@ const ExperimentalApp = () => {
{LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute)}
-
- {/* Redirects for old paths */}
- {REDIRECTS.map(toRedirectRoute)}
+
+ {/* Redirects for old paths */}
+ {REDIRECTS.map(toRedirectRoute)}
);
};
diff --git a/src/apps/experimental/AppLayout.tsx b/src/apps/experimental/AppLayout.tsx
index 71824e0d73..1f4860637c 100644
--- a/src/apps/experimental/AppLayout.tsx
+++ b/src/apps/experimental/AppLayout.tsx
@@ -1,18 +1,17 @@
import React, { useCallback, useEffect, useState } from 'react';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
-import { ThemeProvider } from '@mui/material/styles';
+import { useTheme } from '@mui/material/styles';
import { Outlet, useLocation } from 'react-router-dom';
-import AppHeader from 'components/AppHeader';
-import Backdrop from 'components/Backdrop';
+import AppBody from 'components/AppBody';
+import ElevationScroll from 'components/ElevationScroll';
+import { DRAWER_WIDTH } from 'components/ResponsiveDrawer';
import { useApi } from 'hooks/useApi';
import { useLocalStorage } from 'hooks/useLocalStorage';
import AppToolbar from './components/AppToolbar';
-import AppDrawer, { DRAWER_WIDTH, isDrawerPath } from './components/drawers/AppDrawer';
-import ElevationScroll from './components/ElevationScroll';
-import theme from './theme';
+import AppDrawer, { isDrawerPath } from './components/drawers/AppDrawer';
import './AppOverrides.scss';
@@ -29,6 +28,7 @@ const AppLayout = () => {
const [ isDrawerActive, setIsDrawerActive ] = useState(appSettings.isDrawerPinned);
const { user } = useApi();
const location = useLocation();
+ const theme = useTheme();
const isDrawerAvailable = isDrawerPath(location.pathname);
const isDrawerOpen = isDrawerActive && isDrawerAvailable && Boolean(user);
@@ -47,67 +47,54 @@ const AppLayout = () => {
}, [ isDrawerActive, setIsDrawerActive ]);
return (
-
-
-
-
- {/*
- * TODO: These components are not used, but views interact with them directly so the need to be
- * present in the dom. We add them in a hidden element to prevent errors.
- */}
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
);
};
diff --git a/src/apps/experimental/components/AppToolbar/index.tsx b/src/apps/experimental/components/AppToolbar/index.tsx
index 0317ae92a3..ed447ae694 100644
--- a/src/apps/experimental/components/AppToolbar/index.tsx
+++ b/src/apps/experimental/components/AppToolbar/index.tsx
@@ -1,22 +1,14 @@
-import ArrowBack from '@mui/icons-material/ArrowBack';
-import MenuIcon from '@mui/icons-material/Menu';
import SearchIcon from '@mui/icons-material/Search';
-import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
-import Toolbar from '@mui/material/Toolbar';
import Tooltip from '@mui/material/Tooltip';
-import Typography from '@mui/material/Typography';
import React, { FC } from 'react';
import { Link, useLocation } from 'react-router-dom';
-import appIcon from 'assets/img/icon-transparent.png';
-import { appRouter } from 'components/router/appRouter';
-import { useApi } from 'hooks/useApi';
+import AppToolbar from 'components/toolbar/AppToolbar';
import globalize from 'scripts/globalize';
import AppTabs from '../tabs/AppTabs';
import { isDrawerPath } from '../drawers/AppDrawer';
-import UserMenuButton from './UserMenuButton';
import RemotePlayButton from './RemotePlayButton';
import SyncPlayButton from './SyncPlayButton';
@@ -25,120 +17,40 @@ interface AppToolbarProps {
onDrawerButtonClick: (event: React.MouseEvent) => void
}
-const onBackButtonClick = () => {
- appRouter.back()
- .catch(err => {
- console.error('[AppToolbar] error calling appRouter.back', err);
- });
-};
-
-const AppToolbar: FC = ({
+const ExperimentalAppToolbar: FC = ({
isDrawerOpen,
onDrawerButtonClick
}) => {
- const { user } = useApi();
- const isUserLoggedIn = Boolean(user);
const location = useLocation();
-
const isDrawerAvailable = isDrawerPath(location.pathname);
- const isBackButtonAvailable = appRouter.canGoBack();
return (
-
- {isUserLoggedIn && isDrawerAvailable && (
-
-
-
-
-
- )}
-
- {isBackButtonAvailable && (
-
-
-
-
-
- )}
-
-
-
-
- Jellyfin
-
-
-
-
-
- {isUserLoggedIn && (
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
>
- )}
-
+ }
+ isDrawerAvailable={isDrawerAvailable}
+ isDrawerOpen={isDrawerOpen}
+ onDrawerButtonClick={onDrawerButtonClick}
+ >
+
+
);
};
-export default AppToolbar;
+export default ExperimentalAppToolbar;
diff --git a/src/apps/experimental/components/drawers/AppDrawer.tsx b/src/apps/experimental/components/drawers/AppDrawer.tsx
index ffd9ba119e..c414e6ba78 100644
--- a/src/apps/experimental/components/drawers/AppDrawer.tsx
+++ b/src/apps/experimental/components/drawers/AppDrawer.tsx
@@ -1,5 +1,7 @@
import React, { FC } from 'react';
-import { Route, Routes } from 'react-router-dom';
+import { Route, Routes, useLocation } from 'react-router-dom';
+
+import ResponsiveDrawer, { ResponsiveDrawerProps } from 'components/ResponsiveDrawer';
import { ASYNC_ADMIN_ROUTES, ASYNC_USER_ROUTES } from '../../routes/asyncRoutes';
import { LEGACY_ADMIN_ROUTES, LEGACY_USER_ROUTES } from '../../routes/legacyRoutes';
@@ -10,7 +12,7 @@ import LiveTvDrawerSection from './dashboard/LiveTvDrawerSection';
import PluginDrawerSection from './dashboard/PluginDrawerSection';
import ServerDrawerSection from './dashboard/ServerDrawerSection';
import MainDrawerContent from './MainDrawerContent';
-import ResponsiveDrawer, { ResponsiveDrawerProps } from './ResponsiveDrawer';
+import { isTabPath } from '../tabs/tabRoutes';
export const DRAWER_WIDTH = 240;
@@ -36,6 +38,20 @@ export const isDrawerPath = (path: string) => (
|| ADMIN_DRAWER_ROUTES.some(route => route.path === path || `/${route.path}` === path)
);
+const Drawer: FC = ({ children, ...props }) => {
+ const location = useLocation();
+ const hasSecondaryToolBar = isTabPath(location.pathname);
+
+ return (
+
+ {children}
+
+ );
+};
+
const AppDrawer: FC = ({
open = false,
onClose,
@@ -48,13 +64,13 @@ const AppDrawer: FC = ({
key={route.path}
path={route.path}
element={
-
-
+
}
/>
))
@@ -65,7 +81,7 @@ const AppDrawer: FC = ({
key={route.path}
path={route.path}
element={
- = ({
-
+
}
/>
))
diff --git a/src/apps/experimental/components/drawers/MainDrawerContent.tsx b/src/apps/experimental/components/drawers/MainDrawerContent.tsx
index f402189cf7..4d2a74b8a9 100644
--- a/src/apps/experimental/components/drawers/MainDrawerContent.tsx
+++ b/src/apps/experimental/components/drawers/MainDrawerContent.tsx
@@ -17,12 +17,12 @@ import ListSubheader from '@mui/material/ListSubheader';
import React, { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
+import ListItemLink from 'components/ListItemLink';
+import { appRouter } from 'components/router/appRouter';
import { useApi } from 'hooks/useApi';
import { useWebConfig } from 'hooks/useWebConfig';
import globalize from 'scripts/globalize';
-import { appRouter } from 'components/router/appRouter';
-import ListItemLink from './ListItemLink';
import LibraryIcon from '../LibraryIcon';
const MainDrawerContent = () => {
diff --git a/src/apps/experimental/components/drawers/dashboard/AdvancedDrawerSection.tsx b/src/apps/experimental/components/drawers/dashboard/AdvancedDrawerSection.tsx
index 7e0bb4e366..5a74c68632 100644
--- a/src/apps/experimental/components/drawers/dashboard/AdvancedDrawerSection.tsx
+++ b/src/apps/experimental/components/drawers/dashboard/AdvancedDrawerSection.tsx
@@ -15,10 +15,9 @@ import ListSubheader from '@mui/material/ListSubheader';
import React from 'react';
import { useLocation } from 'react-router-dom';
+import ListItemLink from 'components/ListItemLink';
import globalize from 'scripts/globalize';
-import ListItemLink from '../ListItemLink';
-
const PLUGIN_PATHS = [
'/installedplugins.html',
'/availableplugins.html',
diff --git a/src/apps/experimental/components/drawers/dashboard/DevicesDrawerSection.tsx b/src/apps/experimental/components/drawers/dashboard/DevicesDrawerSection.tsx
index cb3cbf33ce..fe3ec09217 100644
--- a/src/apps/experimental/components/drawers/dashboard/DevicesDrawerSection.tsx
+++ b/src/apps/experimental/components/drawers/dashboard/DevicesDrawerSection.tsx
@@ -8,10 +8,9 @@ import ListSubheader from '@mui/material/ListSubheader';
import React from 'react';
import { useLocation } from 'react-router-dom';
+import ListItemLink from 'components/ListItemLink';
import globalize from 'scripts/globalize';
-import ListItemLink from '../ListItemLink';
-
const DLNA_PATHS = [
'/dlnasettings.html',
'/dlnaprofiles.html'
diff --git a/src/apps/experimental/components/drawers/dashboard/LiveTvDrawerSection.tsx b/src/apps/experimental/components/drawers/dashboard/LiveTvDrawerSection.tsx
index 505973b82c..e3d20e154a 100644
--- a/src/apps/experimental/components/drawers/dashboard/LiveTvDrawerSection.tsx
+++ b/src/apps/experimental/components/drawers/dashboard/LiveTvDrawerSection.tsx
@@ -6,10 +6,9 @@ import ListItemText from '@mui/material/ListItemText';
import ListSubheader from '@mui/material/ListSubheader';
import React from 'react';
+import ListItemLink from 'components/ListItemLink';
import globalize from 'scripts/globalize';
-import ListItemLink from '../ListItemLink';
-
const LiveTvDrawerSection = () => {
return (
{
const { api } = useApi();
const [ pagesInfo, setPagesInfo ] = useState([]);
diff --git a/src/apps/experimental/components/drawers/dashboard/ServerDrawerSection.tsx b/src/apps/experimental/components/drawers/dashboard/ServerDrawerSection.tsx
index 388c1feeeb..2ed6b73f86 100644
--- a/src/apps/experimental/components/drawers/dashboard/ServerDrawerSection.tsx
+++ b/src/apps/experimental/components/drawers/dashboard/ServerDrawerSection.tsx
@@ -8,10 +8,9 @@ import ListSubheader from '@mui/material/ListSubheader';
import React from 'react';
import { useLocation } from 'react-router-dom';
+import ListItemLink from 'components/ListItemLink';
import globalize from 'scripts/globalize';
-import ListItemLink from '../ListItemLink';
-
const LIBRARY_PATHS = [
'/library.html',
'/librarydisplay.html',
diff --git a/src/apps/stable/App.tsx b/src/apps/stable/App.tsx
index 3ad72bcb84..8285cbc9ec 100644
--- a/src/apps/stable/App.tsx
+++ b/src/apps/stable/App.tsx
@@ -1,8 +1,7 @@
import React from 'react';
import { Navigate, Outlet, Route, Routes } from 'react-router-dom';
-import AppHeader from 'components/AppHeader';
-import Backdrop from 'components/Backdrop';
+import AppBody from 'components/AppBody';
import ServerContentPage from 'components/ServerContentPage';
import ConnectionRequired from 'components/ConnectionRequired';
import { toAsyncPageRoute } from 'components/router/AsyncRoute';
@@ -14,15 +13,9 @@ import { REDIRECTS } from './routes/_redirects';
import { toRedirectRoute } from 'components/router/Redirect';
const Layout = () => (
- <>
-
-
-
-
-
-
-
- >
+
+
+
);
const StableApp = () => (
@@ -53,10 +46,10 @@ const StableApp = () => (
{/* Suppress warnings for unhandled routes */}
-
- {/* Redirects for old paths */}
- {REDIRECTS.map(toRedirectRoute)}
+
+ {/* Redirects for old paths */}
+ {REDIRECTS.map(toRedirectRoute)}
);
diff --git a/src/components/AppBody.tsx b/src/components/AppBody.tsx
new file mode 100644
index 0000000000..5d10bca2c9
--- /dev/null
+++ b/src/components/AppBody.tsx
@@ -0,0 +1,24 @@
+import React, { FC, useEffect } from 'react';
+import viewContainer from './viewContainer';
+
+/**
+ * A simple component that includes the correct structure for ViewManager pages
+ * to exist alongside standard React pages.
+ */
+const AppBody: FC = ({ children }) => {
+ useEffect(() => () => {
+ // Reset view container state on unload
+ viewContainer.reset();
+ }, []);
+
+ return (
+ <>
+
+
+ {children}
+
+ >
+ );
+};
+
+export default AppBody;
diff --git a/src/components/AppHeader.tsx b/src/components/AppHeader.tsx
index 941d36a940..1ce6a6a8c4 100644
--- a/src/components/AppHeader.tsx
+++ b/src/components/AppHeader.tsx
@@ -1,19 +1,29 @@
-import React, { useEffect } from 'react';
+import React, { FC, useEffect } from 'react';
-const AppHeader = () => {
+interface AppHeaderParams {
+ isHidden?: boolean
+}
+
+const AppHeader: FC = ({
+ isHidden = false
+}) => {
useEffect(() => {
// Initialize the UI components after first render
import('../scripts/libraryMenu');
}, []);
return (
- <>
+ /**
+ * NOTE: These components are not used with the new layouts, but legacy views interact with the elements
+ * directly so they need to be present in the DOM. We use display: none to hide them and prevent errors.
+ */
+
- >
+
);
};
diff --git a/src/apps/experimental/components/ElevationScroll.tsx b/src/components/ElevationScroll.tsx
similarity index 100%
rename from src/apps/experimental/components/ElevationScroll.tsx
rename to src/components/ElevationScroll.tsx
diff --git a/src/apps/experimental/components/drawers/ListItemLink.tsx b/src/components/ListItemLink.tsx
similarity index 100%
rename from src/apps/experimental/components/drawers/ListItemLink.tsx
rename to src/components/ListItemLink.tsx
diff --git a/src/apps/experimental/components/drawers/ResponsiveDrawer.tsx b/src/components/ResponsiveDrawer.tsx
similarity index 87%
rename from src/apps/experimental/components/drawers/ResponsiveDrawer.tsx
rename to src/components/ResponsiveDrawer.tsx
index 1f7a554cf4..bc463cca2f 100644
--- a/src/apps/experimental/components/drawers/ResponsiveDrawer.tsx
+++ b/src/components/ResponsiveDrawer.tsx
@@ -5,14 +5,13 @@ import SwipeableDrawer from '@mui/material/SwipeableDrawer';
import Toolbar from '@mui/material/Toolbar';
import useMediaQuery from '@mui/material/useMediaQuery';
import React, { FC, useCallback } from 'react';
-import { useLocation } from 'react-router-dom';
import browser from 'scripts/browser';
-import { DRAWER_WIDTH } from './AppDrawer';
-import { isTabPath } from '../tabs/tabRoutes';
+export const DRAWER_WIDTH = 240;
export interface ResponsiveDrawerProps {
+ hasSecondaryToolBar?: boolean
open: boolean
onClose: () => void
onOpen: () => void
@@ -20,18 +19,17 @@ export interface ResponsiveDrawerProps {
const ResponsiveDrawer: FC = ({
children,
+ hasSecondaryToolBar = false,
open = false,
onClose,
onOpen
}) => {
- const location = useLocation();
const isSmallScreen = useMediaQuery((theme: Theme) => theme.breakpoints.up('sm'));
const isLargeScreen = useMediaQuery((theme: Theme) => theme.breakpoints.up('lg'));
- const isTallToolbar = isTabPath(location.pathname) && !isLargeScreen;
const getToolbarStyles = useCallback((theme: Theme) => ({
- marginBottom: isTallToolbar ? theme.spacing(6) : 0
- }), [ isTallToolbar ]);
+ marginBottom: (hasSecondaryToolBar && !isLargeScreen) ? theme.spacing(6) : 0
+ }), [ hasSecondaryToolBar, isLargeScreen ]);
return ( isSmallScreen ? (
/* DESKTOP DRAWER */
diff --git a/src/components/router/AsyncRoute.tsx b/src/components/router/AsyncRoute.tsx
index 9ed49544fb..031e5700ea 100644
--- a/src/components/router/AsyncRoute.tsx
+++ b/src/components/router/AsyncRoute.tsx
@@ -1,4 +1,4 @@
-import loadable from '@loadable/component';
+import loadable, { LoadableComponent } from '@loadable/component';
import React from 'react';
import { Route } from 'react-router-dom';
@@ -10,13 +10,18 @@ export enum AsyncRouteType {
export interface AsyncRoute {
/** The URL path for this route. */
path: string
- /** The relative path to the page component in the routes directory. */
- page: string
- /** The route should use the page component from the experimental app. */
+ /**
+ * The relative path to the page component in the routes directory.
+ * Will fallback to using the `path` value if not specified.
+ */
+ page?: string
+ /** The page element to render. */
+ element?: LoadableComponent
+ /** The page type used to load the correct page element. */
type?: AsyncRouteType
}
-interface AsyncPageProps {
+export interface AsyncPageProps {
/** The relative path to the page component in the routes directory. */
page: string
}
@@ -31,14 +36,19 @@ const StableAsyncPage = loadable(
{ cacheKey: (props: AsyncPageProps) => props.page }
);
-export const toAsyncPageRoute = ({ path, page, type = AsyncRouteType.Stable }: AsyncRoute) => (
- {
+ const Element = element
+ || (
type === AsyncRouteType.Experimental ?
- :
-
- )}
- />
-);
+ ExperimentalAsyncPage :
+ StableAsyncPage
+ );
+
+ return (
+ }
+ />
+ );
+};
diff --git a/src/components/toolbar/AppToolbar.tsx b/src/components/toolbar/AppToolbar.tsx
new file mode 100644
index 0000000000..8ed92eee16
--- /dev/null
+++ b/src/components/toolbar/AppToolbar.tsx
@@ -0,0 +1,129 @@
+import ArrowBack from '@mui/icons-material/ArrowBack';
+import MenuIcon from '@mui/icons-material/Menu';
+import Box from '@mui/material/Box';
+import IconButton from '@mui/material/IconButton';
+import Toolbar from '@mui/material/Toolbar';
+import Tooltip from '@mui/material/Tooltip';
+import Typography from '@mui/material/Typography';
+import React, { FC, ReactNode } from 'react';
+import { Link } from 'react-router-dom';
+
+import appIcon from 'assets/img/icon-transparent.png';
+import { appRouter } from 'components/router/appRouter';
+import { useApi } from 'hooks/useApi';
+import globalize from 'scripts/globalize';
+
+import UserMenuButton from './UserMenuButton';
+
+interface AppToolbarProps {
+ buttons?: ReactNode
+ isDrawerAvailable: boolean
+ isDrawerOpen: boolean
+ onDrawerButtonClick: (event: React.MouseEvent) => void
+}
+
+const onBackButtonClick = () => {
+ appRouter.back()
+ .catch(err => {
+ console.error('[AppToolbar] error calling appRouter.back', err);
+ });
+};
+
+const AppToolbar: FC = ({
+ buttons,
+ children,
+ isDrawerAvailable,
+ isDrawerOpen,
+ onDrawerButtonClick
+}) => {
+ const { user } = useApi();
+ const isUserLoggedIn = Boolean(user);
+
+ const isBackButtonAvailable = appRouter.canGoBack();
+
+ return (
+
+ {isUserLoggedIn && isDrawerAvailable && (
+
+
+
+
+
+ )}
+
+ {isBackButtonAvailable && (
+
+
+
+
+
+ )}
+
+
+
+
+ Jellyfin
+
+
+
+ {children}
+
+ {isUserLoggedIn && (
+ <>
+
+ {buttons}
+
+
+
+
+
+ >
+ )}
+
+ );
+};
+
+export default AppToolbar;
diff --git a/src/apps/experimental/components/AppToolbar/menus/AppUserMenu.tsx b/src/components/toolbar/AppUserMenu.tsx
similarity index 100%
rename from src/apps/experimental/components/AppToolbar/menus/AppUserMenu.tsx
rename to src/components/toolbar/AppUserMenu.tsx
diff --git a/src/apps/experimental/components/AppToolbar/UserMenuButton.tsx b/src/components/toolbar/UserMenuButton.tsx
similarity index 96%
rename from src/apps/experimental/components/AppToolbar/UserMenuButton.tsx
rename to src/components/toolbar/UserMenuButton.tsx
index 89f18669e9..fa47ce85e6 100644
--- a/src/apps/experimental/components/AppToolbar/UserMenuButton.tsx
+++ b/src/components/toolbar/UserMenuButton.tsx
@@ -2,11 +2,11 @@ import IconButton from '@mui/material/IconButton';
import Tooltip from '@mui/material/Tooltip';
import React, { useCallback, useState } from 'react';
+import UserAvatar from 'components/UserAvatar';
import { useApi } from 'hooks/useApi';
import globalize from 'scripts/globalize';
-import AppUserMenu, { ID } from './menus/AppUserMenu';
-import UserAvatar from 'components/UserAvatar';
+import AppUserMenu, { ID } from './AppUserMenu';
const UserMenuButton = () => {
const { user } = useApi();
diff --git a/src/apps/experimental/theme.ts b/src/themes/theme.ts
similarity index 96%
rename from src/apps/experimental/theme.ts
rename to src/themes/theme.ts
index d3f84366be..e223e24c51 100644
--- a/src/apps/experimental/theme.ts
+++ b/src/themes/theme.ts
@@ -1,5 +1,6 @@
import { createTheme } from '@mui/material/styles';
+/** The default Jellyfin app theme for mui */
const theme = createTheme({
palette: {
mode: 'dark',