Migrate to mui grid v2

This commit is contained in:
schroda
2024-09-14 03:01:07 +02:00
parent 6c01c222c3
commit fe6757f308
5 changed files with 38 additions and 57 deletions

View File

@@ -16,8 +16,8 @@ import React, {
useRef, useRef,
useState, useState,
} from 'react'; } from 'react';
import Grid, { GridTypeMap } from '@mui/material/Grid'; import Grid, { Grid2TypeMap as GridTypeMap } from '@mui/material/Grid2';
import Box from '@mui/material/Box'; import Box, { BoxProps } from '@mui/material/Box';
import { GridItemProps, GridStateSnapshot, VirtuosoGrid } from 'react-virtuoso'; import { GridItemProps, GridStateSnapshot, VirtuosoGrid } from 'react-virtuoso';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@@ -35,7 +35,7 @@ import { useResizeObserver } from '@/util/useResizeObserver.tsx';
import { useNavBarContext } from '@/components/context/NavbarContext.tsx'; import { useNavBarContext } from '@/components/context/NavbarContext.tsx';
const GridContainer = React.forwardRef<HTMLDivElement, GridTypeMap['props']>(({ children, ...props }, ref) => ( const GridContainer = React.forwardRef<HTMLDivElement, GridTypeMap['props']>(({ children, ...props }, ref) => (
<Grid {...props} ref={ref} container sx={{ paddingLeft: '5px', paddingRight: '13px' }}> <Grid {...props} ref={ref} container spacing={1}>
{children} {children}
</Grid> </Grid>
)); ));
@@ -51,7 +51,7 @@ const GridItemContainerWithDimension = (
// MUI GridProps and Virtuoso GridItemProps use different types for the "ref" prop which conflict with each other // MUI GridProps and Virtuoso GridItemProps use different types for the "ref" prop which conflict with each other
return ({ children, ...itemProps }: GridTypeMap['props'] & Omit<Partial<GridItemProps>, 'ref'>) => ( return ({ children, ...itemProps }: GridTypeMap['props'] & Omit<Partial<GridItemProps>, 'ref'>) => (
<Grid {...itemProps} item xs={columnsPerItem} sx={{ width: '100%', paddingTop: '8px', paddingLeft: '8px' }}> <Grid {...itemProps} size={columnsPerItem}>
{children} {children}
</Grid> </Grid>
); );
@@ -109,10 +109,8 @@ const HorizontalGrid = forwardRef(
ref={ref} ref={ref}
container container
spacing={1} spacing={1}
style={{ sx={{
margin: 0,
width: '100%', width: '100%',
padding: '5px',
overflowX: 'auto', overflowX: 'auto',
display: '-webkit-inline-box', display: '-webkit-inline-box',
flexWrap: 'nowrap', flexWrap: 'nowrap',
@@ -232,6 +230,7 @@ export interface IMangaGridProps
loadMore: () => void; loadMore: () => void;
horizontal?: boolean | undefined; horizontal?: boolean | undefined;
noFaces?: boolean | undefined; noFaces?: boolean | undefined;
gridWrapperProps?: Omit<BoxProps, 'ref'>;
} }
export const MangaGrid: React.FC<IMangaGridProps> = ({ export const MangaGrid: React.FC<IMangaGridProps> = ({
@@ -250,6 +249,7 @@ export const MangaGrid: React.FC<IMangaGridProps> = ({
handleSelection, handleSelection,
mode, mode,
retry, retry,
gridWrapperProps,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -353,13 +353,7 @@ export const MangaGrid: React.FC<IMangaGridProps> = ({
} }
return ( return (
<div <Box {...gridWrapperProps} ref={gridWrapperRef} sx={{ ...gridWrapperProps?.sx, overflow: 'hidden' }}>
ref={gridWrapperRef}
style={{
overflow: 'hidden',
paddingBottom: '13px',
}}
>
{horizontal ? ( {horizontal ? (
<HorizontalGrid <HorizontalGrid
ref={gridRef} ref={gridRef}
@@ -389,6 +383,6 @@ export const MangaGrid: React.FC<IMangaGridProps> = ({
mode={mode} mode={mode}
/> />
)} )}
</div> </Box>
); );
}; };

View File

@@ -44,6 +44,7 @@ export const LibraryMangaGrid: React.FC<LibraryMangaGridProps> = ({
return ( return (
<MangaGrid <MangaGrid
gridWrapperProps={{ sx: { p: 1 } }}
{...gridProps} {...gridProps}
hasNextPage={false} hasNextPage={false}
loadMore={() => undefined} loadMore={() => undefined}

View File

@@ -13,5 +13,5 @@ type TMangaBaseGrid = Omit<IMangaGridProps['mangas'][number], 'downloadCount' |
export function BaseMangaGrid(props: Omit<IMangaGridProps, 'mangas'> & { mangas: TMangaBaseGrid[] }) { export function BaseMangaGrid(props: Omit<IMangaGridProps, 'mangas'> & { mangas: TMangaBaseGrid[] }) {
const { mangas } = props; const { mangas } = props;
return <MangaGrid {...props} mangas={mangas as IMangaGridProps['mangas']} />; return <MangaGrid gridWrapperProps={{ sx: { p: 1 } }} {...props} mangas={mangas as IMangaGridProps['mangas']} />;
} }

View File

@@ -13,6 +13,7 @@ import React, { useCallback, useContext, useEffect, useMemo, useState } from 're
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
import { StringParam, useQueryParam } from 'use-query-params'; import { StringParam, useQueryParam } from 'use-query-params';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Box from '@mui/material/Box';
import { requestManager } from '@/lib/requests/RequestManager.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts';
import { useLocalStorage } from '@/util/useStorage.tsx'; import { useLocalStorage } from '@/util/useStorage.tsx';
import { langSortCmp, sourceDefualtLangs, sourceForcedDefaultLangs } from '@/util/language'; import { langSortCmp, sourceDefualtLangs, sourceForcedDefaultLangs } from '@/util/language';
@@ -144,7 +145,7 @@ const SourceSearchPreview = React.memo(
return ( return (
<> <>
<Card sx={{ margin: '10px' }}> <Card sx={{ mb: 1 }}>
<CardActionArea component={Link} to={`/sources/${id}?query=${searchString}`} sx={{ p: 3 }}> <CardActionArea component={Link} to={`/sources/${id}?query=${searchString}`} sx={{ p: 3 }}>
<Typography variant="h5">{displayName}</Typography> <Typography variant="h5">{displayName}</Typography>
<Typography variant="caption">{translateExtensionLanguage(lang)}</Typography> <Typography variant="caption">{translateExtensionLanguage(lang)}</Typography>
@@ -167,6 +168,7 @@ const SourceSearchPreview = React.memo(
/> />
) : ( ) : (
<BaseMangaGrid <BaseMangaGrid
gridWrapperProps={{ sx: { px: 0 } }}
mangas={mangas} mangas={mangas}
isLoading={isLoading} isLoading={isLoading}
hasNextPage={false} hasNextPage={false}
@@ -275,17 +277,18 @@ export const SearchAll: React.FC = () => {
} }
return ( return (
<> <Box sx={{ p: 1 }}>
{sourcesSortedByResult.map((source) => ( {sourcesSortedByResult.map((source, index) => (
<SourceSearchPreview <Box key={source.id} sx={{ pb: index + 1 !== sourcesSortedByResult.length ? 2 : 0 }}>
key={source.id} <SourceSearchPreview
source={source} source={source}
onSearchRequestFinished={updateSourceLoadingState} onSearchRequestFinished={updateSourceLoadingState}
searchString={searchString} searchString={searchString}
emptyQuery={!query} emptyQuery={!query}
mode={isMigrateMode ? 'migrate.select' : 'source'} mode={isMigrateMode ? 'migrate.select' : 'source'}
/> />
</Box>
))} ))}
</> </Box>
); );
}; };

View File

@@ -49,37 +49,20 @@ import { MangaIdInfo } from '@/lib/data/Mangas.ts';
const ContentTypeMenu = styled('div')(({ theme }) => ({ const ContentTypeMenu = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
position: 'fixed', position: 'sticky',
top: '64px',
width: '100%', width: '100%',
zIndex: 1, zIndex: 1,
padding: theme.spacing(1),
gap: theme.spacing(1),
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
[theme.breakpoints.down('sm')]: {
top: '56px', // header height
},
})); }));
const ContentTypeButton = styled(Button)(() => ({ const ContentTypeButton = styled(Button)(() => ({}));
marginTop: '13px',
marginBottom: '13px',
marginLeft: '13px',
}));
const StyledGridWrapper = styled(Box, { shouldForwardProp: (prop) => prop !== 'hasContent' })<{ hasContent: boolean }>( const StyledGridWrapper = styled(Box)(() => ({
({ theme, hasContent }) => ({ minHeight: '100%',
// 62.5px ContentTypeMenu height (- padding of grid + grid item) position: 'relative',
marginTop: `calc(62.5px ${hasContent ? '- 8px' : ''})`, }));
// header height - ContentTypeMenu height
minHeight: 'calc(100vh - 64px - 62.5px)',
position: 'relative',
[theme.breakpoints.down('sm')]: {
// 62.5px ContentTypeMenu - 8px margin diff header height (56px) (- padding of grid item)
marginTop: `calc(62.5px - 8px ${hasContent ? '- 8px' : ''})`,
// header height (+ 8px margin) - footer height - ContentTypeMenu height
minHeight: 'calc(100vh - 64px - 64px - 62.5px)',
},
}),
);
export enum SourceContentType { export enum SourceContentType {
POPULAR, POPULAR,
@@ -212,7 +195,7 @@ const useSourceManga = (
export function SourceMangas() { export function SourceMangas() {
const { t } = useTranslation(); const { t } = useTranslation();
const { setTitle, setAction } = useContext(NavBarContext); const { setTitle, setAction, appBarHeight } = useContext(NavBarContext);
const { sourceId } = useParams<{ sourceId: string }>(); const { sourceId } = useParams<{ sourceId: string }>();
@@ -226,7 +209,6 @@ export function SourceMangas() {
}>().state ?? {}; }>().state ?? {};
const [isFirstRender, setIsFirstRender] = useState(true); const [isFirstRender, setIsFirstRender] = useState(true);
useEffect(() => { useEffect(() => {
setIsFirstRender(false); setIsFirstRender(false);
}, []); }, []);
@@ -444,8 +426,8 @@ export function SourceMangas() {
}, [t, source]); }, [t, source]);
return ( return (
<StyledGridWrapper hasContent={!!mangas.length}> <StyledGridWrapper>
<ContentTypeMenu> <ContentTypeMenu sx={{ top: `${appBarHeight}px` }}>
<ContentTypeButton <ContentTypeButton
variant={contentType === SourceContentType.POPULAR ? 'contained' : 'outlined'} variant={contentType === SourceContentType.POPULAR ? 'contained' : 'outlined'}
startIcon={<FavoriteIcon />} startIcon={<FavoriteIcon />}
@@ -473,6 +455,7 @@ export function SourceMangas() {
</ContentTypeMenu> </ContentTypeMenu>
<BaseMangaGrid <BaseMangaGrid
key={contentType} key={contentType}
gridWrapperProps={{ sx: { px: 1, pb: 1 } }}
mangas={mangas} mangas={mangas}
hasNextPage={hasNextPage} hasNextPage={hasNextPage}
loadMore={loadMore} loadMore={loadMore}