1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Update mui based layout ui

This commit is contained in:
Bill Thornton 2023-11-28 10:26:14 -05:00
parent bfbdffdff5
commit 4e7f0136f7
14 changed files with 163 additions and 194 deletions

View file

@ -1,7 +1,8 @@
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import { useTheme } from '@mui/material/styles'; import { type Theme } from '@mui/material/styles';
import React, { FC, useCallback, useEffect, useState } from 'react'; import useMediaQuery from '@mui/material/useMediaQuery';
import React, { FC, useCallback, useState } from 'react';
import { Outlet, useLocation } from 'react-router-dom'; import { Outlet, useLocation } from 'react-router-dom';
import AppBody from 'components/AppBody'; import AppBody from 'components/AppBody';
@ -9,7 +10,6 @@ import AppToolbar from 'components/toolbar/AppToolbar';
import ElevationScroll from 'components/ElevationScroll'; import ElevationScroll from 'components/ElevationScroll';
import { DRAWER_WIDTH } from 'components/ResponsiveDrawer'; import { DRAWER_WIDTH } from 'components/ResponsiveDrawer';
import { useApi } from 'hooks/useApi'; import { useApi } from 'hooks/useApi';
import { useLocalStorage } from 'hooks/useLocalStorage';
import AppDrawer from './components/drawer/AppDrawer'; import AppDrawer from './components/drawer/AppDrawer';
@ -19,45 +19,37 @@ interface AppLayoutProps {
drawerlessPaths: string[] drawerlessPaths: string[]
} }
interface DashboardAppSettings {
isDrawerPinned: boolean
}
const DEFAULT_APP_SETTINGS: DashboardAppSettings = {
isDrawerPinned: false
};
const AppLayout: FC<AppLayoutProps> = ({ const AppLayout: FC<AppLayoutProps> = ({
drawerlessPaths drawerlessPaths
}) => { }) => {
const [ appSettings, setAppSettings ] = useLocalStorage<DashboardAppSettings>('DashboardAppSettings', DEFAULT_APP_SETTINGS); const [ isDrawerActive, setIsDrawerActive ] = useState(false);
const [ isDrawerActive, setIsDrawerActive ] = useState(appSettings.isDrawerPinned);
const location = useLocation(); const location = useLocation();
const theme = useTheme();
const { user } = useApi(); const { user } = useApi();
const isDrawerAvailable = !drawerlessPaths.some(path => location.pathname.startsWith(`/${path}`)); const isSmallScreen = useMediaQuery((t: Theme) => t.breakpoints.up('sm'));
const isDrawerAvailable = !isSmallScreen
&& !drawerlessPaths.some(path => location.pathname.startsWith(`/${path}`));
const isDrawerOpen = isDrawerActive && isDrawerAvailable && Boolean(user); const isDrawerOpen = isDrawerActive && isDrawerAvailable && Boolean(user);
useEffect(() => {
if (isDrawerActive !== appSettings.isDrawerPinned) {
setAppSettings({
...appSettings,
isDrawerPinned: isDrawerActive
});
}
}, [ appSettings, isDrawerActive, setAppSettings ]);
const onToggleDrawer = useCallback(() => { const onToggleDrawer = useCallback(() => {
setIsDrawerActive(!isDrawerActive); setIsDrawerActive(!isDrawerActive);
}, [ isDrawerActive, setIsDrawerActive ]); }, [ isDrawerActive, setIsDrawerActive ]);
return ( return (
<Box sx={{ display: 'flex' }}> <Box sx={{ display: 'flex' }}>
<ElevationScroll elevate={isDrawerOpen}> <ElevationScroll elevate={false}>
<AppBar <AppBar
position='fixed' position='fixed'
sx={{ zIndex: (muiTheme) => muiTheme.zIndex.drawer + 1 }} sx={{
width: {
xs: '100%',
sm: `calc(100% - ${DRAWER_WIDTH}px)`
},
ml: {
xs: 0,
sm: `${DRAWER_WIDTH}px`
}
}}
> >
<AppToolbar <AppToolbar
isDrawerAvailable={isDrawerAvailable} isDrawerAvailable={isDrawerAvailable}
@ -77,24 +69,7 @@ const AppLayout: FC<AppLayoutProps> = ({
component='main' component='main'
sx={{ sx={{
width: '100%', width: '100%',
flexGrow: 1, flexGrow: 1
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}),
marginLeft: 0,
...(isDrawerAvailable && {
marginLeft: {
sm: `-${DRAWER_WIDTH}px`
}
}),
...(isDrawerActive && {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
}),
marginLeft: 0
})
}} }}
> >
<AppBody> <AppBody>

View file

@ -1,5 +1,8 @@
import ListItem from '@mui/material/ListItem';
import List from '@mui/material/List';
import React, { FC } from 'react'; import React, { FC } from 'react';
import DrawerHeaderLink from 'apps/experimental/components/drawers/DrawerHeaderLink';
import ResponsiveDrawer, { ResponsiveDrawerProps } from 'components/ResponsiveDrawer'; import ResponsiveDrawer, { ResponsiveDrawerProps } from 'components/ResponsiveDrawer';
import ServerDrawerSection from './sections/ServerDrawerSection'; import ServerDrawerSection from './sections/ServerDrawerSection';
@ -18,6 +21,11 @@ const AppDrawer: FC<ResponsiveDrawerProps> = ({
onClose={onClose} onClose={onClose}
onOpen={onOpen} onOpen={onOpen}
> >
<List disablePadding>
<ListItem disablePadding>
<DrawerHeaderLink />
</ListItem>
</List>
<ServerDrawerSection /> <ServerDrawerSection />
<DevicesDrawerSection /> <DevicesDrawerSection />
<LiveTvDrawerSection /> <LiveTvDrawerSection />

View file

@ -1,46 +1,28 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useState } from 'react';
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import { useTheme } from '@mui/material/styles'; import { type Theme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import { Outlet, useLocation } from 'react-router-dom'; import { Outlet, useLocation } from 'react-router-dom';
import AppBody from 'components/AppBody'; import AppBody from 'components/AppBody';
import ElevationScroll from 'components/ElevationScroll'; import ElevationScroll from 'components/ElevationScroll';
import { DRAWER_WIDTH } from 'components/ResponsiveDrawer'; import { DRAWER_WIDTH } from 'components/ResponsiveDrawer';
import { useApi } from 'hooks/useApi'; import { useApi } from 'hooks/useApi';
import { useLocalStorage } from 'hooks/useLocalStorage';
import AppToolbar from './components/AppToolbar'; import AppToolbar from './components/AppToolbar';
import AppDrawer, { isDrawerPath } from './components/drawers/AppDrawer'; import AppDrawer, { isDrawerPath } from './components/drawers/AppDrawer';
import './AppOverrides.scss'; import './AppOverrides.scss';
interface ExperimentalAppSettings {
isDrawerPinned: boolean
}
const DEFAULT_EXPERIMENTAL_APP_SETTINGS: ExperimentalAppSettings = {
isDrawerPinned: false
};
const AppLayout = () => { const AppLayout = () => {
const [ appSettings, setAppSettings ] = useLocalStorage<ExperimentalAppSettings>('ExperimentalAppSettings', DEFAULT_EXPERIMENTAL_APP_SETTINGS); const [ isDrawerActive, setIsDrawerActive ] = useState(false);
const [ isDrawerActive, setIsDrawerActive ] = useState(appSettings.isDrawerPinned);
const { user } = useApi(); const { user } = useApi();
const location = useLocation(); const location = useLocation();
const theme = useTheme();
const isDrawerAvailable = isDrawerPath(location.pathname); const isSmallScreen = useMediaQuery((t: Theme) => t.breakpoints.up('sm'));
const isDrawerOpen = isDrawerActive && isDrawerAvailable && Boolean(user); const isDrawerAvailable = isDrawerPath(location.pathname) && Boolean(user);
const isDrawerOpen = isDrawerActive && isDrawerAvailable;
useEffect(() => {
if (isDrawerActive !== appSettings.isDrawerPinned) {
setAppSettings({
...appSettings,
isDrawerPinned: isDrawerActive
});
}
}, [ appSettings, isDrawerActive, setAppSettings ]);
const onToggleDrawer = useCallback(() => { const onToggleDrawer = useCallback(() => {
setIsDrawerActive(!isDrawerActive); setIsDrawerActive(!isDrawerActive);
@ -48,46 +30,43 @@ const AppLayout = () => {
return ( return (
<Box sx={{ display: 'flex' }}> <Box sx={{ display: 'flex' }}>
<ElevationScroll elevate={isDrawerOpen}> <ElevationScroll elevate={false}>
<AppBar <AppBar
position='fixed' position='fixed'
sx={{ zIndex: (muiTheme) => muiTheme.zIndex.drawer + 1 }} sx={{
width: {
xs: '100%',
sm: isDrawerAvailable ? `calc(100% - ${DRAWER_WIDTH}px)` : '100%'
},
ml: {
xs: 0,
sm: isDrawerAvailable ? DRAWER_WIDTH : 0
}
}}
> >
<AppToolbar <AppToolbar
isDrawerAvailable={!isSmallScreen && isDrawerAvailable}
isDrawerOpen={isDrawerOpen} isDrawerOpen={isDrawerOpen}
onDrawerButtonClick={onToggleDrawer} onDrawerButtonClick={onToggleDrawer}
/> />
</AppBar> </AppBar>
</ElevationScroll> </ElevationScroll>
{
user && (
<AppDrawer <AppDrawer
open={isDrawerOpen} open={isDrawerOpen}
onClose={onToggleDrawer} onClose={onToggleDrawer}
onOpen={onToggleDrawer} onOpen={onToggleDrawer}
/> />
)
}
<Box <Box
component='main' component='main'
sx={{ sx={{
width: '100%', width: '100%',
flexGrow: 1, flexGrow: 1
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}),
marginLeft: 0,
...(isDrawerAvailable && {
marginLeft: {
sm: `-${DRAWER_WIDTH}px`
}
}),
...(isDrawerActive && {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
}),
marginLeft: 0
})
}} }}
> >
<AppBody> <AppBody>

View file

@ -20,7 +20,7 @@ $mui-bp-xl: 1536px;
} }
// Fix the padding of some pages // Fix the padding of some pages
.homePage.libraryPage, // Home page .homePage.libraryPage.withTabs, // Home page
.libraryPage:not(.withTabs) { // Tabless library pages .libraryPage:not(.withTabs) { // Tabless library pages
padding-top: 3.25rem !important; padding-top: 3.25rem !important;
} }

View file

@ -8,22 +8,22 @@ import AppToolbar from 'components/toolbar/AppToolbar';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
import AppTabs from '../tabs/AppTabs'; import AppTabs from '../tabs/AppTabs';
import { isDrawerPath } from '../drawers/AppDrawer';
import RemotePlayButton from './RemotePlayButton'; import RemotePlayButton from './RemotePlayButton';
import SyncPlayButton from './SyncPlayButton'; import SyncPlayButton from './SyncPlayButton';
import { isTabPath } from '../tabs/tabRoutes'; import { isTabPath } from '../tabs/tabRoutes';
interface AppToolbarProps { interface AppToolbarProps {
isDrawerAvailable: boolean
isDrawerOpen: boolean isDrawerOpen: boolean
onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void
} }
const ExperimentalAppToolbar: FC<AppToolbarProps> = ({ const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
isDrawerAvailable,
isDrawerOpen, isDrawerOpen,
onDrawerButtonClick onDrawerButtonClick
}) => { }) => {
const location = useLocation(); const location = useLocation();
const isDrawerAvailable = isDrawerPath(location.pathname);
const isTabsAvailable = isTabPath(location.pathname); const isTabsAvailable = isTabPath(location.pathname);
return ( return (

View file

@ -1,11 +1,9 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { useLocation } from 'react-router-dom';
import ResponsiveDrawer, { ResponsiveDrawerProps } from 'components/ResponsiveDrawer'; import ResponsiveDrawer, { ResponsiveDrawerProps } from 'components/ResponsiveDrawer';
import { ASYNC_USER_ROUTES } from '../../routes/asyncRoutes'; import { ASYNC_USER_ROUTES } from '../../routes/asyncRoutes';
import { LEGACY_USER_ROUTES } from '../../routes/legacyRoutes'; import { LEGACY_USER_ROUTES } from '../../routes/legacyRoutes';
import { isTabPath } from '../tabs/tabRoutes';
import MainDrawerContent from './MainDrawerContent'; import MainDrawerContent from './MainDrawerContent';
@ -27,20 +25,14 @@ const AppDrawer: FC<ResponsiveDrawerProps> = ({
open = false, open = false,
onClose, onClose,
onOpen onOpen
}) => { }) => (
const location = useLocation();
const hasSecondaryToolBar = isTabPath(location.pathname);
return (
<ResponsiveDrawer <ResponsiveDrawer
hasSecondaryToolBar={hasSecondaryToolBar}
open={open} open={open}
onClose={onClose} onClose={onClose}
onOpen={onOpen} onOpen={onOpen}
> >
<MainDrawerContent /> <MainDrawerContent />
</ResponsiveDrawer> </ResponsiveDrawer>
); );
};
export default AppDrawer; export default AppDrawer;

View file

@ -0,0 +1,33 @@
import Box from '@mui/material/Box';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import React from 'react';
import { useApi } from 'hooks/useApi';
import { useSystemInfo } from 'hooks/useSystemInfo';
import ListItemLink from 'components/ListItemLink';
import appIcon from 'assets/img/icon-transparent.png';
const DrawerHeaderLink = () => {
const { api } = useApi();
const { data: systemInfo } = useSystemInfo(api);
return (
<ListItemLink to='/'>
<ListItemIcon sx={{ minWidth: 56 }}>
<Box
component='img'
src={appIcon}
sx={{ height: '2.5rem' }}
/>
</ListItemIcon>
<ListItemText
primary={systemInfo?.ServerName || 'Jellyfin'}
primaryTypographyProps={{ variant: 'h6' }}
secondary={systemInfo?.Version}
/>
</ListItemLink>);
};
export default DrawerHeaderLink;

View file

@ -1,7 +1,5 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto';
import type { SystemInfo } from '@jellyfin/sdk/lib/generated-client/models/system-info';
import { getUserViewsApi } from '@jellyfin/sdk/lib/utils/api/user-views-api'; import { getUserViewsApi } from '@jellyfin/sdk/lib/utils/api/user-views-api';
import { getSystemApi } from '@jellyfin/sdk/lib/utils/api/system-api';
import Dashboard from '@mui/icons-material/Dashboard'; import Dashboard from '@mui/icons-material/Dashboard';
import Edit from '@mui/icons-material/Edit'; import Edit from '@mui/icons-material/Edit';
import Favorite from '@mui/icons-material/Favorite'; import Favorite from '@mui/icons-material/Favorite';
@ -24,11 +22,11 @@ import { useWebConfig } from 'hooks/useWebConfig';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
import LibraryIcon from '../LibraryIcon'; import LibraryIcon from '../LibraryIcon';
import DrawerHeaderLink from './DrawerHeaderLink';
const MainDrawerContent = () => { const MainDrawerContent = () => {
const { api, user } = useApi(); const { api, user } = useApi();
const location = useLocation(); const location = useLocation();
const [ systemInfo, setSystemInfo ] = useState<SystemInfo>();
const [ userViews, setUserViews ] = useState<BaseItemDto[]>([]); const [ userViews, setUserViews ] = useState<BaseItemDto[]>([]);
const webConfig = useWebConfig(); const webConfig = useWebConfig();
@ -45,15 +43,6 @@ const MainDrawerContent = () => {
console.warn('[MainDrawer] failed to fetch user views', err); console.warn('[MainDrawer] failed to fetch user views', err);
setUserViews([]); setUserViews([]);
}); });
getSystemApi(api)
.getSystemInfo()
.then(({ data }) => {
setSystemInfo(data);
})
.catch(err => {
console.warn('[MainDrawer] failed to fetch system info', err);
});
} else { } else {
setUserViews([]); setUserViews([]);
} }
@ -62,7 +51,10 @@ const MainDrawerContent = () => {
return ( return (
<> <>
{/* MAIN LINKS */} {/* MAIN LINKS */}
<List> <List sx={{ paddingTop: 0 }}>
<ListItem disablePadding>
<DrawerHeaderLink />
</ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemLink to='/home.html' selected={isHomeSelected}> <ListItemLink to='/home.html' selected={isHomeSelected}>
<ListItemIcon> <ListItemIcon>
@ -168,17 +160,6 @@ const MainDrawerContent = () => {
</List> </List>
</> </>
)} )}
{/* FOOTER */}
<Divider style={{ marginTop: 'auto' }} />
<List>
<ListItem>
<ListItemText
primary={systemInfo?.ServerName ? systemInfo.ServerName : 'Jellyfin'}
secondary={systemInfo?.Version ? `v${systemInfo.Version}` : ''}
/>
</ListItem>
</List>
</> </>
); );
}; };

View file

@ -1,4 +1,6 @@
import Box from '@mui/material/Box';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { DRAWER_WIDTH } from './ResponsiveDrawer';
const Backdrop = () => { const Backdrop = () => {
useEffect(() => { useEffect(() => {
@ -8,7 +10,14 @@ const Backdrop = () => {
return ( return (
<> <>
<div className='backdropContainer' /> <Box
className='backdropContainer'
sx={{
left: {
sm: DRAWER_WIDTH
}
}}
/>
<div className='backgroundContainer' /> <div className='backgroundContainer' />
</> </>
); );

View file

@ -1,17 +1,15 @@
import { Theme } from '@mui/material/styles'; import type { Theme } from '@mui/material/styles';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Drawer from '@mui/material/Drawer'; import Drawer from '@mui/material/Drawer';
import SwipeableDrawer from '@mui/material/SwipeableDrawer'; import SwipeableDrawer from '@mui/material/SwipeableDrawer';
import Toolbar from '@mui/material/Toolbar';
import useMediaQuery from '@mui/material/useMediaQuery'; import useMediaQuery from '@mui/material/useMediaQuery';
import React, { FC, useCallback } from 'react'; import React, { FC } from 'react';
import browser from 'scripts/browser'; import browser from 'scripts/browser';
export const DRAWER_WIDTH = 240; export const DRAWER_WIDTH = 240;
export interface ResponsiveDrawerProps { export interface ResponsiveDrawerProps {
hasSecondaryToolBar?: boolean
open: boolean open: boolean
onClose: () => void onClose: () => void
onOpen: () => void onOpen: () => void
@ -19,17 +17,11 @@ export interface ResponsiveDrawerProps {
const ResponsiveDrawer: FC<ResponsiveDrawerProps> = ({ const ResponsiveDrawer: FC<ResponsiveDrawerProps> = ({
children, children,
hasSecondaryToolBar = false,
open = false, open = false,
onClose, onClose,
onOpen onOpen
}) => { }) => {
const isSmallScreen = useMediaQuery((theme: Theme) => theme.breakpoints.up('sm')); const isSmallScreen = useMediaQuery((theme: Theme) => theme.breakpoints.up('sm'));
const isLargeScreen = useMediaQuery((theme: Theme) => theme.breakpoints.up('lg'));
const getToolbarStyles = useCallback((theme: Theme) => ({
marginBottom: (hasSecondaryToolBar && !isLargeScreen) ? theme.spacing(6) : 0
}), [ hasSecondaryToolBar, isLargeScreen ]);
return ( isSmallScreen ? ( return ( isSmallScreen ? (
/* DESKTOP DRAWER */ /* DESKTOP DRAWER */
@ -42,14 +34,9 @@ const ResponsiveDrawer: FC<ResponsiveDrawerProps> = ({
boxSizing: 'border-box' boxSizing: 'border-box'
} }
}} }}
variant='persistent' variant='permanent'
anchor='left' anchor='left'
open={open}
> >
<Toolbar
variant='dense'
sx={getToolbarStyles}
/>
{children} {children}
</Drawer> </Drawer>
) : ( ) : (
@ -65,10 +52,6 @@ const ResponsiveDrawer: FC<ResponsiveDrawerProps> = ({
keepMounted: true // Better open performance on mobile. keepMounted: true // Better open performance on mobile.
}} }}
> >
<Toolbar
variant='dense'
sx={getToolbarStyles}
/>
<Box <Box
role='presentation' role='presentation'
// Close the drawer when the content is clicked // Close the drawer when the content is clicked

View file

@ -4,11 +4,9 @@ import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography';
import React, { FC, ReactNode } from 'react'; import React, { FC, ReactNode } from 'react';
import { Link, useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import appIcon from 'assets/img/icon-transparent.png';
import { appRouter } from 'components/router/appRouter'; import { appRouter } from 'components/router/appRouter';
import { useApi } from 'hooks/useApi'; import { useApi } from 'hooks/useApi';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
@ -84,35 +82,6 @@ const AppToolbar: FC<AppToolbarProps> = ({
</Tooltip> </Tooltip>
)} )}
<Box
component={Link}
to='/'
color='inherit'
aria-label={globalize.translate('Home')}
sx={{
ml: 2,
display: 'inline-flex',
textDecoration: 'none'
}}
>
<Box
component='img'
src={appIcon}
sx={{
height: '2rem',
marginInlineEnd: 1
}}
/>
<Typography
variant='h6'
noWrap
component='div'
sx={{ display: { xs: 'none', sm: 'inline-block' } }}
>
Jellyfin
</Typography>
</Box>
{children} {children}
{isUserLoggedIn && isUserMenuAvailable && ( {isUserLoggedIn && isUserMenuAvailable && (

View file

@ -1,8 +1,8 @@
import { getQuickConnectApi } from '@jellyfin/sdk/lib/utils/api/quick-connect-api'; import { getQuickConnectApi } from '@jellyfin/sdk/lib/utils/api/quick-connect-api';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { AxiosRequestConfig } from 'axios'; import type { AxiosRequestConfig } from 'axios';
import { JellyfinApiContext, useApi } from './useApi'; import { type JellyfinApiContext, useApi } from './useApi';
const fetchQuickConnectEnabled = async ( const fetchQuickConnectEnabled = async (
apiContext: JellyfinApiContext, apiContext: JellyfinApiContext,

View file

@ -0,0 +1,23 @@
import { useQuery } from '@tanstack/react-query';
import type { Api } from '@jellyfin/sdk';
import { getSystemApi } from '@jellyfin/sdk/lib/utils/api/system-api';
import type { AxiosRequestConfig } from 'axios';
const fetchSystemInfo = async (
api: Api | undefined,
options: AxiosRequestConfig
) => {
if (!api) throw new Error('No API instance available');
const response = await getSystemApi(api)
.getSystemInfo(options);
return response.data;
};
export const useSystemInfo = (api: Api | undefined) => {
return useQuery({
queryKey: [ 'SystemInfo' ],
queryFn: ({ signal }) => fetchSystemInfo(api, { signal }),
enabled: !!api
});
};

View file

@ -1,5 +1,7 @@
import { createTheme } from '@mui/material/styles'; import { createTheme } from '@mui/material/styles';
const LIST_ICON_WIDTH = 36;
/** The default Jellyfin app theme for mui */ /** The default Jellyfin app theme for mui */
const theme = createTheme({ const theme = createTheme({
palette: { palette: {
@ -49,11 +51,26 @@ const theme = createTheme({
variant: 'filled' variant: 'filled'
} }
}, },
MuiListItemIcon: {
styleOverrides: {
root: {
minWidth: LIST_ICON_WIDTH
}
}
},
MuiListSubheader: { MuiListSubheader: {
styleOverrides: { styleOverrides: {
root: { root: {
// NOTE: Added for drawer subheaders, but maybe it won't work in other cases? // NOTE: Added for drawer subheaders, but maybe it won't work in other cases?
backgroundColor: 'inherit' backgroundColor: 'inherit',
position: 'initial'
}
}
},
MuiListItemText: {
styleOverrides: {
inset: {
paddingLeft: LIST_ICON_WIDTH
} }
} }
} }