Skip to content

Commit

Permalink
feat: migrated books to virtuoso
Browse files Browse the repository at this point in the history
  • Loading branch information
mbret committed Jul 31, 2024
1 parent a879bc7 commit 13cc34f
Show file tree
Hide file tree
Showing 13 changed files with 288 additions and 204 deletions.
236 changes: 132 additions & 104 deletions packages/web/src/books/bookList/BookList.tsx
Original file line number Diff line number Diff line change
@@ -1,143 +1,171 @@
import React, { useCallback, FC, memo, ReactNode } from "react"
import { Box, useTheme } from "@mui/material"
import React, { useCallback, FC, memo, ReactNode, ComponentProps } from "react"
import { Box, BoxProps, Stack, useTheme } from "@mui/material"
import { useWindowSize } from "react-use"
import { BookListGridItem } from "./BookListGridItem"
import { LibrarySorting } from "../../library/states"
import { BookListListItem } from "./BookListListItem"
import { ReactWindowList } from "../../common/lists/ReactWindowList"
import { ListActionViewMode } from "../../common/lists/ListActionsToolbar"
import { BookListCompactItem } from "./BookListCompactItem"
import { useListItemHeight } from "./useListItemHeight"
import { VirtuosoList } from "../../common/lists/VirtuosoList"

const ItemListContainer = ({
children,
isLast,
borders = false
borders = false,
...rest
}: {
children: ReactNode
isLast: boolean
borders?: boolean
}) => (
} & BoxProps) => (
<Box
style={{
flex: 1,
alignItems: "center",
display: "flex",
height: "100%"
display: "flex"
}}
{...(!isLast &&
borders && {
borderBottom: "1px solid",
borderColor: "grey.200"
})}
{...rest}
>
{children}
</Box>
)

export const BookList: FC<{
viewMode?: ListActionViewMode
renderHeader?: () => React.ReactNode
headerHeight?: number
sorting?: LibrarySorting
isHorizontal?: boolean
style?: React.CSSProperties
itemWidth?: number
data: string[]
density?: "dense" | "large"
onItemClick?: (id: string) => void
withBookActions?: boolean
static?: boolean
}> = memo((props) => {
const {
viewMode = "grid",
renderHeader,
headerHeight,
density = "large",
isHorizontal = false,
style,
data,
itemWidth,
onItemClick,
withBookActions
} = props
const windowSize = useWindowSize()
const theme = useTheme()
const dynamicNumberOfItems = Math.round(windowSize.width / 200)
const itemsPerRow =
viewMode === "grid" && !isHorizontal
? dynamicNumberOfItems > 0
? dynamicNumberOfItems
: dynamicNumberOfItems
: 1
const adjustedRatioWhichConsiderBottom = theme.custom.coverAverageRatio - 0.1
const { itemHeight, itemMargin } = useListItemHeight({
density,
viewMode
})
export const BookList = memo(
(
props: {
viewMode?: ListActionViewMode
sorting?: LibrarySorting
isHorizontal?: boolean
itemWidth?: number
density?: "dense" | "large"
onItemClick?: (id: string) => void
withBookActions?: boolean
static?: boolean
} & ComponentProps<typeof VirtuosoList>
) => {
const {
viewMode = "grid",
density = "large",
isHorizontal = false,
style,
data,
itemWidth,
onItemClick,
withBookActions,
static: isStatic,
...rest
} = props
const windowSize = useWindowSize()
const theme = useTheme()
const dynamicNumberOfItems = Math.round(windowSize.width / 200)
const itemsPerRow =
viewMode === "grid" && !isHorizontal
? dynamicNumberOfItems > 0
? dynamicNumberOfItems
: dynamicNumberOfItems
: 1
const adjustedRatioWhichConsiderBottom =
theme.custom.coverAverageRatio - 0.1
const { itemHeight, itemMargin } = useListItemHeight({
density,
viewMode
})
const computedItemWidth = itemWidth
? itemWidth
: Math.floor(windowSize.width / itemsPerRow)
const computedItemHeight =
itemHeight ||
Math.floor(computedItemWidth / adjustedRatioWhichConsiderBottom)

// const rowBorderColor = theme.palette.grey[100]
const rowRenderer = useCallback(
(index: number, item: string, { size }: { size: number }) => {
const isLast = index === size - 1

const rowRenderer = useCallback(
(item: string, _: number, isLast: boolean) => {
return viewMode === "grid" ? (
<BookListGridItem bookId={item} />
) : viewMode === "list" ? (
<ItemListContainer isLast={isLast}>
<BookListListItem
return viewMode === "grid" ? (
<BookListGridItem
bookId={item}
itemHeight={(itemHeight || 0) - itemMargin}
onItemClick={onItemClick}
withDrawerActions={withBookActions}
pl={1}
style={{
height: computedItemHeight,
width: "100%"
}}
/>
</ItemListContainer>
) : (
<ItemListContainer isLast={isLast} borders>
<BookListCompactItem
bookId={item}
itemHeight={(itemHeight || 0) - itemMargin}
onItemClick={onItemClick}
withDrawerActions={withBookActions}
pl={1}
/>
</ItemListContainer>
) : viewMode === "list" ? (
<ItemListContainer isLast={isLast} height={itemHeight}>
<BookListListItem
bookId={item}
itemHeight={(itemHeight || 0) - itemMargin}
onItemClick={onItemClick}
withDrawerActions={withBookActions}
pl={1}
/>
</ItemListContainer>
) : (
<ItemListContainer isLast={isLast} borders height={itemHeight}>
<BookListCompactItem
bookId={item}
itemHeight={(itemHeight || 0) - itemMargin}
onItemClick={onItemClick}
withDrawerActions={withBookActions}
pl={1}
/>
</ItemListContainer>
)
},
[
viewMode,
itemHeight,
itemMargin,
onItemClick,
withBookActions,
computedItemHeight
]
)

if (isStatic) {
return (
<Box
style={style}
px={isHorizontal ? 0 : 1}
display="flex"
flexDirection="column"
>
{data?.map((item, index) => (
<Box key={item} height={itemHeight}>
{rowRenderer(index, item, { size: data.length })}
</Box>
))}
</Box>
)
},
[viewMode, itemHeight, itemMargin, onItemClick, withBookActions]
)
}

if (props.static) {
return (
<Box
style={style}
px={isHorizontal ? 0 : 1}
display="flex"
flexDirection="column"
>
{data.map((item, index) => (
<Box key={item} height={itemHeight}>
{rowRenderer(item, index, index === data.length - 1)}
</Box>
))}
</Box>
<Stack style={style}>
<VirtuosoList
data={data}
rowRenderer={rowRenderer}
itemsPerRow={itemsPerRow}
// layout={isHorizontal ? "horizontal" : "vertical"}
{...rest}
/>
</Stack>
)
}

return (
<Box style={style} display="flex">
<ReactWindowList
data={data}
rowRenderer={rowRenderer}
itemsPerRow={itemsPerRow}
preferredRatio={adjustedRatioWhichConsiderBottom}
headerHeight={headerHeight}
renderHeader={renderHeader}
layout={isHorizontal ? "horizontal" : "vertical"}
itemWidth={itemWidth}
// only used when list layout
itemHeight={itemHeight}
/>
</Box>
)
})
// return (
// <Stack flex={1}>
// <VirtualizedList
// data={data}
// rowRenderer={rowRenderer}
// itemsPerRow={itemsPerRow}
// style={style}
// {...rest}
// />
// </Stack>
// )
}
)
16 changes: 9 additions & 7 deletions packages/web/src/books/bookList/BookListGridItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, memo } from "react"
import { ComponentProps, FC, memo } from "react"
import { Box, Typography, styled, useTheme } from "@mui/material"
import { MoreVert } from "@mui/icons-material"
import { bookActionDrawerSignal } from "../drawer/BookActionsDrawer"
Expand All @@ -8,20 +8,21 @@ import { BookListCoverContainer } from "./BookListCoverContainer"
import { useCSS } from "../../common/utils"
import { getMetadataFromBook } from "../metadata"

const ContainerBox = styled("div")`
const ContainerBox = styled(Box)`
cursor: pointer;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
padding: ${({ theme }) => theme.spacing(1)};
-webkit-tap-highlight-color: transparent;
`

export const BookListGridItem: FC<{
bookId: string
onItemClick?: (id: string) => void
}> = memo(({ bookId, onItemClick }) => {
export const BookListGridItem: FC<
{
bookId: string
onItemClick?: (id: string) => void
} & ComponentProps<typeof ContainerBox>
> = memo(({ bookId, onItemClick, ...rest }) => {
const { data: item } = useBook({
id: bookId
})
Expand All @@ -37,6 +38,7 @@ export const BookListGridItem: FC<{
if (onItemClick) return onItemClick(bookId)
return onDefaultItemClick(bookId)
}}
{...rest}
>
<BookListCoverContainer
bookId={bookId}
Expand Down
18 changes: 12 additions & 6 deletions packages/web/src/collections/list/CollectionList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, FC, memo, ComponentProps, useMemo } from "react"
import { Box, List, Stack } from "@mui/material"
import { List, Stack } from "@mui/material"
import { CollectionListItemList } from "./CollectionListItemList"
import { CollectionDocType } from "@oboku/shared"
import { DeepReadonlyObject } from "rxdb"
Expand All @@ -13,10 +13,7 @@ export const CollectionList: FC<
viewMode?: ListActionViewMode
itemMode?: ComponentProps<typeof CollectionListItemList>["viewMode"]
static?: boolean
} & Pick<
ComponentProps<typeof VirtuosoList>,
"onStateChange" | "restoreStateFrom" | "data" | "style" | "renderHeader"
>
} & ComponentProps<typeof VirtuosoList>
> = memo(({ itemMode, ...props }) => {
const { viewMode, data, onItemClick, static: isStatic, ...rest } = props
const windowSize = useWindowSize()
Expand Down Expand Up @@ -52,7 +49,7 @@ export const CollectionList: FC<
if (isStatic) {
return (
<List disablePadding>
{data.map((item, index) => (
{data?.map((item, index) => (
<Stack height={itemHeight} key={item}>
{rowRenderer(index, item)}
</Stack>
Expand All @@ -69,4 +66,13 @@ export const CollectionList: FC<
{...rest}
/>
)

// return (
// <VirtualizedList
// data={data}
// itemsPerRow={itemsPerRow}
// rowRenderer={rowRenderer}
// {...rest}
// />
// )
})
2 changes: 1 addition & 1 deletion packages/web/src/common/lists/ListActionsToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { SortByDialog } from "../../books/bookList/SortByDialog"

export type ListActionSorting = ComponentProps<typeof SortByDialog>["value"]
export type ListActionViewMode = "grid" | "list" | "compact"
export type ListActionViewMode = "grid" | "list" | "compact" | "horizontal"

export const ViewModeIconButton = ({
viewMode,
Expand Down
Loading

0 comments on commit 13cc34f

Please sign in to comment.