Refactor layout components
This commit is contained in:
parent
b590636303
commit
5f7b005626
7 changed files with 68 additions and 61 deletions
|
@ -9,14 +9,8 @@ import { api } from '/@/renderer/api';
|
||||||
import { controller } from '/@/renderer/api/controller';
|
import { controller } from '/@/renderer/api/controller';
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import { AlbumListQuery, LibraryItem } from '/@/renderer/api/types';
|
import { AlbumListQuery, LibraryItem } from '/@/renderer/api/types';
|
||||||
import {
|
import { PageHeader, SearchInput, VirtualInfiniteGridRef } from '/@/renderer/components';
|
||||||
PageHeader,
|
import { FilterBar, LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||||
Paper,
|
|
||||||
SearchInput,
|
|
||||||
SpinnerIcon,
|
|
||||||
VirtualInfiniteGridRef,
|
|
||||||
} from '/@/renderer/components';
|
|
||||||
import { LibraryHeaderBar } from '/@/renderer/features/shared';
|
|
||||||
import { useContainerQuery } from '/@/renderer/hooks';
|
import { useContainerQuery } from '/@/renderer/hooks';
|
||||||
import {
|
import {
|
||||||
AlbumListFilter,
|
AlbumListFilter,
|
||||||
|
@ -209,14 +203,9 @@ export const AlbumListHeader = ({
|
||||||
<LibraryHeaderBar>
|
<LibraryHeaderBar>
|
||||||
<LibraryHeaderBar.PlayButton onClick={() => handlePlay(playButtonBehavior)} />
|
<LibraryHeaderBar.PlayButton onClick={() => handlePlay(playButtonBehavior)} />
|
||||||
<LibraryHeaderBar.Title>{title || 'Albums'}</LibraryHeaderBar.Title>
|
<LibraryHeaderBar.Title>{title || 'Albums'}</LibraryHeaderBar.Title>
|
||||||
<Paper
|
<LibraryHeaderBar.Badge isLoading={itemCount === null || itemCount === undefined}>
|
||||||
fw="600"
|
{itemCount}
|
||||||
px="1rem"
|
</LibraryHeaderBar.Badge>
|
||||||
py="0.3rem"
|
|
||||||
radius="sm"
|
|
||||||
>
|
|
||||||
{itemCount === null || itemCount === undefined ? <SpinnerIcon /> : itemCount}
|
|
||||||
</Paper>
|
|
||||||
</LibraryHeaderBar>
|
</LibraryHeaderBar>
|
||||||
<Group>
|
<Group>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
|
@ -227,14 +216,14 @@ export const AlbumListHeader = ({
|
||||||
</Group>
|
</Group>
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Paper p="1rem">
|
<FilterBar>
|
||||||
<AlbumListHeaderFilters
|
<AlbumListHeaderFilters
|
||||||
customFilters={customFilters}
|
customFilters={customFilters}
|
||||||
gridRef={gridRef}
|
gridRef={gridRef}
|
||||||
itemCount={itemCount}
|
itemCount={itemCount}
|
||||||
tableRef={tableRef}
|
tableRef={tableRef}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</FilterBar>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,13 +7,7 @@ import { useQueryClient } from '@tanstack/react-query';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import {
|
import { PageHeader, SearchInput, VirtualInfiniteGridRef } from '/@/renderer/components';
|
||||||
PageHeader,
|
|
||||||
Paper,
|
|
||||||
SearchInput,
|
|
||||||
SpinnerIcon,
|
|
||||||
VirtualInfiniteGridRef,
|
|
||||||
} from '/@/renderer/components';
|
|
||||||
import { LibraryHeaderBar } from '/@/renderer/features/shared';
|
import { LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||||
import { useContainerQuery } from '/@/renderer/hooks';
|
import { useContainerQuery } from '/@/renderer/hooks';
|
||||||
import {
|
import {
|
||||||
|
@ -25,6 +19,7 @@ import {
|
||||||
import { ListDisplayType } from '/@/renderer/types';
|
import { ListDisplayType } from '/@/renderer/types';
|
||||||
import { AlbumArtistListHeaderFilters } from '/@/renderer/features/artists/components/album-artist-list-header-filters';
|
import { AlbumArtistListHeaderFilters } from '/@/renderer/features/artists/components/album-artist-list-header-filters';
|
||||||
import { useAlbumArtistListContext } from '/@/renderer/features/artists/context/album-artist-list-context';
|
import { useAlbumArtistListContext } from '/@/renderer/features/artists/context/album-artist-list-context';
|
||||||
|
import { FilterBar } from '../../shared/components/filter-bar';
|
||||||
|
|
||||||
interface AlbumArtistListHeaderProps {
|
interface AlbumArtistListHeaderProps {
|
||||||
gridRef: MutableRefObject<VirtualInfiniteGridRef | null>;
|
gridRef: MutableRefObject<VirtualInfiniteGridRef | null>;
|
||||||
|
@ -154,14 +149,9 @@ export const AlbumArtistListHeader = ({
|
||||||
>
|
>
|
||||||
<LibraryHeaderBar>
|
<LibraryHeaderBar>
|
||||||
<LibraryHeaderBar.Title>Album Artists</LibraryHeaderBar.Title>
|
<LibraryHeaderBar.Title>Album Artists</LibraryHeaderBar.Title>
|
||||||
<Paper
|
<LibraryHeaderBar.Badge isLoading={itemCount === null || itemCount === undefined}>
|
||||||
fw="600"
|
{itemCount}
|
||||||
px="1rem"
|
</LibraryHeaderBar.Badge>
|
||||||
py="0.3rem"
|
|
||||||
radius="sm"
|
|
||||||
>
|
|
||||||
{itemCount === null || itemCount === undefined ? <SpinnerIcon /> : itemCount}
|
|
||||||
</Paper>
|
|
||||||
</LibraryHeaderBar>
|
</LibraryHeaderBar>
|
||||||
<Group>
|
<Group>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
|
@ -172,12 +162,12 @@ export const AlbumArtistListHeader = ({
|
||||||
</Group>
|
</Group>
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Paper p="1rem">
|
<FilterBar>
|
||||||
<AlbumArtistListHeaderFilters
|
<AlbumArtistListHeaderFilters
|
||||||
gridRef={gridRef}
|
gridRef={gridRef}
|
||||||
tableRef={tableRef}
|
tableRef={tableRef}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</FilterBar>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
13
src/renderer/features/shared/components/filter-bar.tsx
Normal file
13
src/renderer/features/shared/components/filter-bar.tsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { PaperProps } from '@mantine/core';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Paper } from '/@/renderer/components';
|
||||||
|
|
||||||
|
const StyledFilterBar = styled(Paper)`
|
||||||
|
z-index: 1;
|
||||||
|
padding: 1rem;
|
||||||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 65%);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FilterBar = ({ children, ...props }: PaperProps) => {
|
||||||
|
return <StyledFilterBar {...props}>{children}</StyledFilterBar>;
|
||||||
|
};
|
|
@ -1,25 +1,25 @@
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { Group, Box } from '@mantine/core';
|
import { Box } from '@mantine/core';
|
||||||
import { TextTitle } from '/@/renderer/components';
|
import { Paper, PaperProps, SpinnerIcon, TextTitle } from '/@/renderer/components';
|
||||||
import { PlayButton as PlayBtn } from '/@/renderer/features/shared/components/play-button';
|
import { PlayButton as PlayBtn } from '/@/renderer/features/shared/components/play-button';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
interface LibraryHeaderBarProps {
|
interface LibraryHeaderBarProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HeaderContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
export const LibraryHeaderBar = ({ children }: LibraryHeaderBarProps) => {
|
export const LibraryHeaderBar = ({ children }: LibraryHeaderBarProps) => {
|
||||||
return (
|
return <HeaderContainer>{children}</HeaderContainer>;
|
||||||
<Group
|
|
||||||
noWrap
|
|
||||||
align="center"
|
|
||||||
h="100%"
|
|
||||||
px="1rem"
|
|
||||||
spacing="md"
|
|
||||||
w="100%"
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Group>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TitleProps {
|
interface TitleProps {
|
||||||
|
@ -54,5 +54,20 @@ const PlayButton = ({ onClick }: PlayButtonProps) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Badge = styled(Paper)`
|
||||||
|
padding: 0.3rem 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface HeaderBadgeProps extends PaperProps {
|
||||||
|
isLoading?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HeaderBadge = ({ children, isLoading, ...props }: HeaderBadgeProps) => {
|
||||||
|
return <Badge {...props}>{isLoading ? <SpinnerIcon /> : children}</Badge>;
|
||||||
|
};
|
||||||
|
|
||||||
LibraryHeaderBar.Title = Title;
|
LibraryHeaderBar.Title = Title;
|
||||||
LibraryHeaderBar.PlayButton = PlayButton;
|
LibraryHeaderBar.PlayButton = PlayButton;
|
||||||
|
LibraryHeaderBar.Badge = HeaderBadge;
|
||||||
|
|
|
@ -7,3 +7,4 @@ export * from './components/library-header-bar';
|
||||||
export * from './mutations/create-favorite-mutation';
|
export * from './mutations/create-favorite-mutation';
|
||||||
export * from './mutations/delete-favorite-mutation';
|
export * from './mutations/delete-favorite-mutation';
|
||||||
export * from './mutations/update-rating-mutation';
|
export * from './mutations/update-rating-mutation';
|
||||||
|
export * from './components/filter-bar';
|
||||||
|
|
|
@ -6,9 +6,9 @@ import { ChangeEvent, MutableRefObject, useCallback } from 'react';
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import { LibraryItem, SongListQuery } from '/@/renderer/api/types';
|
import { LibraryItem, SongListQuery } from '/@/renderer/api/types';
|
||||||
import { PageHeader, Paper, SearchInput, SpinnerIcon } from '/@/renderer/components';
|
import { PageHeader, SearchInput } from '/@/renderer/components';
|
||||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||||
import { LibraryHeaderBar } from '/@/renderer/features/shared';
|
import { FilterBar, LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||||
import { SongListHeaderFilters } from '/@/renderer/features/songs/components/song-list-header-filters';
|
import { SongListHeaderFilters } from '/@/renderer/features/songs/components/song-list-header-filters';
|
||||||
import { useSongListContext } from '/@/renderer/features/songs/context/song-list-context';
|
import { useSongListContext } from '/@/renderer/features/songs/context/song-list-context';
|
||||||
import { useContainerQuery } from '/@/renderer/hooks';
|
import { useContainerQuery } from '/@/renderer/hooks';
|
||||||
|
@ -119,14 +119,9 @@ export const SongListHeader = ({
|
||||||
<LibraryHeaderBar>
|
<LibraryHeaderBar>
|
||||||
<LibraryHeaderBar.PlayButton onClick={() => handlePlay(playButtonBehavior)} />
|
<LibraryHeaderBar.PlayButton onClick={() => handlePlay(playButtonBehavior)} />
|
||||||
<LibraryHeaderBar.Title>{title || 'Tracks'}</LibraryHeaderBar.Title>
|
<LibraryHeaderBar.Title>{title || 'Tracks'}</LibraryHeaderBar.Title>
|
||||||
<Paper
|
<LibraryHeaderBar.Badge isLoading={itemCount === null || itemCount === undefined}>
|
||||||
fw="600"
|
{itemCount}
|
||||||
px="1rem"
|
</LibraryHeaderBar.Badge>
|
||||||
py="0.3rem"
|
|
||||||
radius="sm"
|
|
||||||
>
|
|
||||||
{itemCount === null || itemCount === undefined ? <SpinnerIcon /> : itemCount}
|
|
||||||
</Paper>
|
|
||||||
</LibraryHeaderBar>
|
</LibraryHeaderBar>
|
||||||
<Group>
|
<Group>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
|
@ -137,13 +132,13 @@ export const SongListHeader = ({
|
||||||
</Group>
|
</Group>
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Paper p="1rem">
|
<FilterBar>
|
||||||
<SongListHeaderFilters
|
<SongListHeaderFilters
|
||||||
customFilters={customFilters}
|
customFilters={customFilters}
|
||||||
itemCount={itemCount}
|
itemCount={itemCount}
|
||||||
tableRef={tableRef}
|
tableRef={tableRef}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</FilterBar>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
transition: position 0.2s ease-in-out;
|
transition: position 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ag-header {
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
.window-frame {
|
.window-frame {
|
||||||
top: 95px;
|
top: 95px;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue