mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-16 21:50:35 +02:00
restructure files onto electron-vite boilerplate
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import { Center, Stack } from '@mantine/core';
|
||||
import { RiAlbumFill, RiUserVoiceFill, RiPlayListFill } from 'react-icons/ri';
|
||||
import { RiAlbumFill, RiPlayListFill, RiUserVoiceFill } from 'react-icons/ri';
|
||||
import { generatePath, useNavigate } from 'react-router-dom';
|
||||
import { SimpleImg } from 'react-simple-img';
|
||||
import { ListChildComponentProps } from 'react-window';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Album, AlbumArtist, Artist, LibraryItem, Playlist, Song } from '/@/renderer/api/types';
|
||||
import { CardRows } from '/@/renderer/components/card';
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/grid-card-controls';
|
||||
import { CardRow, PlayQueueAddOptions, Play, CardRoute } from '/@/renderer/types';
|
||||
import { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/renderer/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
columnIndex: number;
|
||||
@@ -131,11 +132,11 @@ const DetailContainer = styled.div`
|
||||
`;
|
||||
|
||||
export const DefaultCard = ({
|
||||
listChildProps,
|
||||
data,
|
||||
columnIndex,
|
||||
controls,
|
||||
data,
|
||||
isHidden,
|
||||
listChildProps,
|
||||
}: BaseGridCardProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -156,10 +157,10 @@ export const DefaultCard = ({
|
||||
case LibraryItem.ALBUM:
|
||||
Placeholder = RiAlbumFill;
|
||||
break;
|
||||
case LibraryItem.ARTIST:
|
||||
case LibraryItem.ALBUM_ARTIST:
|
||||
Placeholder = RiUserVoiceFill;
|
||||
break;
|
||||
case LibraryItem.ALBUM_ARTIST:
|
||||
case LibraryItem.ARTIST:
|
||||
Placeholder = RiUserVoiceFill;
|
||||
break;
|
||||
case LibraryItem.PLAYLIST:
|
||||
@@ -172,8 +173,8 @@ export const DefaultCard = ({
|
||||
|
||||
return (
|
||||
<DefaultCardContainer
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
$itemGap={controls.itemGap}
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
onClick={() => navigate(path)}
|
||||
>
|
||||
<InnerCardContainer>
|
||||
@@ -221,25 +222,25 @@ export const DefaultCard = ({
|
||||
|
||||
return (
|
||||
<DefaultCardContainer
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
$isHidden={isHidden}
|
||||
$itemGap={controls.itemGap}
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
>
|
||||
<InnerCardContainer>
|
||||
<ImageContainer>
|
||||
<Skeleton
|
||||
visible
|
||||
radius="sm"
|
||||
visible
|
||||
/>
|
||||
</ImageContainer>
|
||||
<DetailContainer>
|
||||
<Stack spacing="sm">
|
||||
{(controls?.cardRows || []).map((row, index) => (
|
||||
<Skeleton
|
||||
key={`${index}-${columnIndex}-${row.arrayProperty}`}
|
||||
visible
|
||||
height={14}
|
||||
key={`${index}-${columnIndex}-${row.arrayProperty}`}
|
||||
radius="sm"
|
||||
visible
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import React, { MouseEvent, useState } from 'react';
|
||||
import type { UnstyledButtonProps } from '@mantine/core';
|
||||
import { RiPlayFill, RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import { _Button } from '/@/renderer/components/button';
|
||||
import type { PlayQueueAddOptions } from '/@/renderer/types';
|
||||
import { Play } from '/@/renderer/types';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { LibraryItem } from '/@/renderer/api/types';
|
||||
import { useHandleGridContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
|
||||
import type { UnstyledButtonProps } from '@mantine/core';
|
||||
|
||||
import React, { MouseEvent, useState } from 'react';
|
||||
import { RiHeartFill, RiHeartLine, RiMoreFill, RiPlayFill } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
PLAYLIST_CONTEXT_MENU_ITEMS,
|
||||
ALBUM_CONTEXT_MENU_ITEMS,
|
||||
ARTIST_CONTEXT_MENU_ITEMS,
|
||||
PLAYLIST_CONTEXT_MENU_ITEMS,
|
||||
} from '../../../features/context-menu/context-menu-items';
|
||||
|
||||
type PlayButtonType = UnstyledButtonProps & React.ComponentPropsWithoutRef<'button'>;
|
||||
import { LibraryItem } from '/@/renderer/api/types';
|
||||
import { _Button } from '/@/renderer/components/button';
|
||||
import { useHandleGridContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { Play } from '/@/renderer/types';
|
||||
|
||||
type PlayButtonType = React.ComponentPropsWithoutRef<'button'> & UnstyledButtonProps;
|
||||
|
||||
const PlayButton = styled.button<PlayButtonType>`
|
||||
position: absolute;
|
||||
@@ -108,10 +111,10 @@ const FavoriteWrapper = styled.span<{ isFavorite: boolean }>`
|
||||
`;
|
||||
|
||||
export const GridCardControls = ({
|
||||
handleFavorite,
|
||||
handlePlayQueueAdd,
|
||||
itemData,
|
||||
itemType,
|
||||
handlePlayQueueAdd,
|
||||
handleFavorite,
|
||||
resetInfiniteLoaderCache,
|
||||
}: {
|
||||
handleFavorite: (options: {
|
||||
@@ -178,9 +181,9 @@ export const GridCardControls = ({
|
||||
<BottomControls>
|
||||
{itemType !== LibraryItem.PLAYLIST && (
|
||||
<SecondaryButton
|
||||
onClick={(e) => handleFavorites(e, itemData?.serverId)}
|
||||
p={5}
|
||||
variant="subtle"
|
||||
onClick={(e) => handleFavorites(e, itemData?.serverId)}
|
||||
>
|
||||
<FavoriteWrapper isFavorite={itemData?.isFavorite}>
|
||||
{isFavorite ? (
|
||||
@@ -196,13 +199,13 @@ export const GridCardControls = ({
|
||||
)}
|
||||
|
||||
<SecondaryButton
|
||||
p={5}
|
||||
variant="subtle"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
handleContextMenu(e, [itemData]);
|
||||
}}
|
||||
p={5}
|
||||
variant="subtle"
|
||||
>
|
||||
<RiMoreFill
|
||||
color="white"
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import { memo } from 'react';
|
||||
import type { ListChildComponentProps } from 'react-window';
|
||||
|
||||
import { memo } from 'react';
|
||||
import { areEqual } from 'react-window';
|
||||
|
||||
import { DefaultCard } from '/@/renderer/components/virtual-grid/grid-card/default-card';
|
||||
import { PosterCard } from '/@/renderer/components/virtual-grid/grid-card/poster-card';
|
||||
import { GridCardData, ListDisplayType } from '/@/renderer/types';
|
||||
|
||||
export const GridCard = memo(({ data, index, style }: ListChildComponentProps) => {
|
||||
const {
|
||||
columnCount,
|
||||
itemCount,
|
||||
cardRows,
|
||||
itemData,
|
||||
itemType,
|
||||
itemGap,
|
||||
playButtonBehavior,
|
||||
handlePlayQueueAdd,
|
||||
handleFavorite,
|
||||
route,
|
||||
columnCount,
|
||||
display,
|
||||
handleFavorite,
|
||||
handlePlayQueueAdd,
|
||||
itemCount,
|
||||
itemData,
|
||||
itemGap,
|
||||
itemType,
|
||||
playButtonBehavior,
|
||||
resetInfiniteLoaderCache,
|
||||
route,
|
||||
} = data as GridCardData;
|
||||
|
||||
const cards = [];
|
||||
@@ -35,7 +37,6 @@ export const GridCard = memo(({ data, index, style }: ListChildComponentProps) =
|
||||
for (let i = startIndex; i <= stopIndex + columnCountToAdd; i += 1) {
|
||||
cards.push(
|
||||
<View
|
||||
key={`card-${i}-${index}`}
|
||||
columnIndex={i}
|
||||
controls={{
|
||||
cardRows,
|
||||
@@ -49,6 +50,7 @@ export const GridCard = memo(({ data, index, style }: ListChildComponentProps) =
|
||||
}}
|
||||
data={itemData[i]}
|
||||
isHidden={i > stopIndex}
|
||||
key={`card-${i}-${index}`}
|
||||
listChildProps={{ index }}
|
||||
/>,
|
||||
);
|
||||
|
||||
@@ -4,11 +4,12 @@ import { generatePath, useNavigate } from 'react-router-dom';
|
||||
import { SimpleImg } from 'react-simple-img';
|
||||
import { ListChildComponentProps } from 'react-window';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Album, AlbumArtist, Artist, LibraryItem, Playlist, Song } from '/@/renderer/api/types';
|
||||
import { CardRows } from '/@/renderer/components/card';
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/grid-card-controls';
|
||||
import { CardRow, PlayQueueAddOptions, Play, CardRoute } from '/@/renderer/types';
|
||||
import { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/renderer/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
columnIndex: number;
|
||||
@@ -119,11 +120,11 @@ const DetailContainer = styled.div`
|
||||
`;
|
||||
|
||||
export const PosterCard = ({
|
||||
listChildProps,
|
||||
data,
|
||||
columnIndex,
|
||||
controls,
|
||||
data,
|
||||
isHidden,
|
||||
listChildProps,
|
||||
}: BaseGridCardProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -144,10 +145,10 @@ export const PosterCard = ({
|
||||
case LibraryItem.ALBUM:
|
||||
Placeholder = RiAlbumFill;
|
||||
break;
|
||||
case LibraryItem.ARTIST:
|
||||
case LibraryItem.ALBUM_ARTIST:
|
||||
Placeholder = RiUserVoiceFill;
|
||||
break;
|
||||
case LibraryItem.ALBUM_ARTIST:
|
||||
case LibraryItem.ARTIST:
|
||||
Placeholder = RiUserVoiceFill;
|
||||
break;
|
||||
case LibraryItem.PLAYLIST:
|
||||
@@ -160,8 +161,8 @@ export const PosterCard = ({
|
||||
|
||||
return (
|
||||
<PosterCardContainer
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
$itemGap={controls.itemGap}
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
>
|
||||
<LinkContainer onClick={() => navigate(path)}>
|
||||
<ImageContainer $isFavorite={data?.userFavorite}>
|
||||
@@ -207,13 +208,13 @@ export const PosterCard = ({
|
||||
|
||||
return (
|
||||
<PosterCardContainer
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
$isHidden={isHidden}
|
||||
$itemGap={controls.itemGap}
|
||||
key={`card-${columnIndex}-${listChildProps.index}`}
|
||||
>
|
||||
<Skeleton
|
||||
visible
|
||||
radius="sm"
|
||||
visible
|
||||
>
|
||||
<ImageContainer />
|
||||
</Skeleton>
|
||||
@@ -221,10 +222,10 @@ export const PosterCard = ({
|
||||
<Stack spacing="sm">
|
||||
{(controls?.cardRows || []).map((row, index) => (
|
||||
<Skeleton
|
||||
key={`${index}-${columnIndex}-${row.arrayProperty}`}
|
||||
visible
|
||||
height={14}
|
||||
key={`${index}-${columnIndex}-${row.arrayProperty}`}
|
||||
radius="sm"
|
||||
visible
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import type { CardRoute, CardRow, ListDisplayType, PlayQueueAddOptions } from '/@/renderer/types';
|
||||
import type { Ref } from 'react';
|
||||
import type { FixedSizeListProps } from 'react-window';
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
import memoize from 'memoize-one';
|
||||
import type { FixedSizeListProps } from 'react-window';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import styled from 'styled-components';
|
||||
import { GridCard } from '/@/renderer/components/virtual-grid/grid-card';
|
||||
import type { CardRow, ListDisplayType, CardRoute, PlayQueueAddOptions } from '/@/renderer/types';
|
||||
|
||||
import { Album, AlbumArtist, Artist, LibraryItem } from '/@/renderer/api/types';
|
||||
import { GridCard } from '/@/renderer/components/virtual-grid/grid-card';
|
||||
|
||||
const createItemData = memoize(
|
||||
(
|
||||
@@ -43,27 +45,27 @@ const createItemData = memoize(
|
||||
const createScrollHandler = memoize((onScroll) => debounce(onScroll, 250));
|
||||
|
||||
export const VirtualGridWrapper = ({
|
||||
refInstance,
|
||||
cardRows,
|
||||
itemGap,
|
||||
itemType,
|
||||
itemWidth,
|
||||
display,
|
||||
itemHeight,
|
||||
itemCount,
|
||||
columnCount,
|
||||
rowCount,
|
||||
initialScrollOffset,
|
||||
display,
|
||||
handleFavorite,
|
||||
handlePlayQueueAdd,
|
||||
itemData,
|
||||
route,
|
||||
onScroll,
|
||||
height,
|
||||
width,
|
||||
initialScrollOffset,
|
||||
itemCount,
|
||||
itemData,
|
||||
itemGap,
|
||||
itemHeight,
|
||||
itemType,
|
||||
itemWidth,
|
||||
onScroll,
|
||||
refInstance,
|
||||
resetInfiniteLoaderCache,
|
||||
route,
|
||||
rowCount,
|
||||
width,
|
||||
...rest
|
||||
}: Omit<FixedSizeListProps, 'ref' | 'itemSize' | 'children' | 'height' | 'width'> & {
|
||||
}: Omit<FixedSizeListProps, 'children' | 'height' | 'itemSize' | 'ref' | 'width'> & {
|
||||
cardRows: CardRow<Album | AlbumArtist | Artist>[];
|
||||
columnCount: number;
|
||||
display: ListDisplayType;
|
||||
@@ -112,9 +114,9 @@ export const VirtualGridWrapper = ({
|
||||
itemCount={rowCount}
|
||||
itemData={memoizedItemData}
|
||||
itemSize={itemHeight}
|
||||
onScroll={memoizedOnScroll}
|
||||
overscanCount={5}
|
||||
width={(width && Number(width)) || 0}
|
||||
onScroll={memoizedOnScroll}
|
||||
>
|
||||
{GridCard}
|
||||
</FixedSizeList>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import type { CardRoute, CardRow, PlayQueueAddOptions } from '/@/renderer/types';
|
||||
import type { FixedSizeListProps } from 'react-window';
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
import {
|
||||
useState,
|
||||
useRef,
|
||||
useMemo,
|
||||
useCallback,
|
||||
forwardRef,
|
||||
Ref,
|
||||
useCallback,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import debounce from 'lodash/debounce';
|
||||
import type { FixedSizeListProps } from 'react-window';
|
||||
import InfiniteLoader from 'react-window-infinite-loader';
|
||||
import { VirtualGridWrapper } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
|
||||
import type { CardRoute, CardRow, PlayQueueAddOptions } from '/@/renderer/types';
|
||||
import { ListDisplayType } from '/@/renderer/types';
|
||||
import { AnyLibraryItem, Genre, LibraryItem } from '/@/renderer/api/types';
|
||||
|
||||
type LibraryItemOrGenre = AnyLibraryItem | Genre;
|
||||
import { AnyLibraryItem, Genre, LibraryItem } from '/@/renderer/api/types';
|
||||
import { VirtualGridWrapper } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
|
||||
import { ListDisplayType } from '/@/renderer/types';
|
||||
|
||||
export type VirtualInfiniteGridRef = {
|
||||
resetLoadMoreItemsCache: () => void;
|
||||
@@ -24,8 +24,10 @@ export type VirtualInfiniteGridRef = {
|
||||
updateItemData: (rule: (item: LibraryItemOrGenre) => LibraryItemOrGenre) => void;
|
||||
};
|
||||
|
||||
type LibraryItemOrGenre = AnyLibraryItem | Genre;
|
||||
|
||||
interface VirtualGridProps
|
||||
extends Omit<FixedSizeListProps, 'children' | 'itemSize' | 'height' | 'width'> {
|
||||
extends Omit<FixedSizeListProps, 'children' | 'height' | 'itemSize' | 'width'> {
|
||||
cardRows: CardRow<any>[];
|
||||
display?: ListDisplayType;
|
||||
fetchFn: (options: { columnCount: number; skip: number; take: number }) => Promise<any>;
|
||||
@@ -49,22 +51,22 @@ interface VirtualGridProps
|
||||
export const VirtualInfiniteGrid = forwardRef(
|
||||
(
|
||||
{
|
||||
cardRows,
|
||||
display,
|
||||
fetchFn,
|
||||
fetchInitialData,
|
||||
handleFavorite,
|
||||
handlePlayQueueAdd,
|
||||
height,
|
||||
initialScrollOffset,
|
||||
itemCount,
|
||||
itemGap,
|
||||
itemSize,
|
||||
itemType,
|
||||
cardRows,
|
||||
route,
|
||||
onScroll,
|
||||
display,
|
||||
handlePlayQueueAdd,
|
||||
minimumBatchSize,
|
||||
fetchFn,
|
||||
fetchInitialData,
|
||||
loading,
|
||||
initialScrollOffset,
|
||||
handleFavorite,
|
||||
height,
|
||||
minimumBatchSize,
|
||||
onScroll,
|
||||
route,
|
||||
width,
|
||||
}: VirtualGridProps,
|
||||
ref: Ref<VirtualInfiniteGridRef>,
|
||||
@@ -78,7 +80,7 @@ export const VirtualInfiniteGrid = forwardRef(
|
||||
fetchInitialData?.() || [],
|
||||
);
|
||||
|
||||
const { itemHeight, rowCount, columnCount } = useMemo(() => {
|
||||
const { columnCount, itemHeight, rowCount } = useMemo(() => {
|
||||
const itemsPerRow = width ? Math.floor(width / (itemSize + itemGap * 2)) : 5;
|
||||
const widthPerItem = Number(width) / itemsPerRow;
|
||||
const itemHeight = widthPerItem + cardRows.length * 26;
|
||||
@@ -165,11 +167,11 @@ export const VirtualInfiniteGrid = forwardRef(
|
||||
return (
|
||||
<>
|
||||
<InfiniteLoader
|
||||
ref={loader}
|
||||
isItemLoaded={(index) => isItemLoaded(index)}
|
||||
itemCount={itemCount || 0}
|
||||
loadMoreItems={debouncedLoadMoreItems}
|
||||
minimumBatchSize={minimumBatchSize}
|
||||
ref={loader}
|
||||
threshold={30}
|
||||
>
|
||||
{({ onItemsRendered, ref: infiniteLoaderRef }) => (
|
||||
@@ -187,6 +189,8 @@ export const VirtualInfiniteGrid = forwardRef(
|
||||
itemHeight={itemHeight}
|
||||
itemType={itemType}
|
||||
itemWidth={itemSize}
|
||||
onItemsRendered={onItemsRendered}
|
||||
onScroll={onScroll}
|
||||
refInstance={(list) => {
|
||||
infiniteLoaderRef(list);
|
||||
listRef.current = list;
|
||||
@@ -200,8 +204,6 @@ export const VirtualInfiniteGrid = forwardRef(
|
||||
route={route}
|
||||
rowCount={rowCount}
|
||||
width={width}
|
||||
onItemsRendered={onItemsRendered}
|
||||
onScroll={onScroll}
|
||||
/>
|
||||
)}
|
||||
</InfiniteLoader>
|
||||
|
||||
Reference in New Issue
Block a user