mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 18:33:33 +00:00
Migrate to Mantine v8 and Design Changes (#961)
* mantine v8 migration * various design changes and improvements
This commit is contained in:
parent
bea55d48a8
commit
c1330d92b2
473 changed files with 12469 additions and 11607 deletions
|
|
@ -1,24 +1,21 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import { RiMoreFill } from 'react-icons/ri';
|
||||
|
||||
import { Button } from '/@/renderer/components/button';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
|
||||
export const ActionsCell = ({ api, context }: ICellRendererParams) => {
|
||||
return (
|
||||
<CellContainer $position="center">
|
||||
<Button
|
||||
compact
|
||||
<CellContainer position="center">
|
||||
<ActionIcon
|
||||
icon="ellipsisHorizontal"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
context.onCellContextMenu(undefined, api, e);
|
||||
}}
|
||||
size="sm"
|
||||
variant="subtle"
|
||||
>
|
||||
<RiMoreFill />
|
||||
</Button>
|
||||
/>
|
||||
</CellContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ import React from 'react';
|
|||
import { generatePath } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Separator } from '/@/renderer/components/separator';
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
export const AlbumArtistCell = ({ data, value }: ICellRendererParams) => {
|
||||
if (value === undefined) {
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Skeleton
|
||||
height="1rem"
|
||||
width="80%"
|
||||
|
|
@ -24,9 +24,9 @@ export const AlbumArtistCell = ({ data, value }: ICellRendererParams) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
|
|
@ -35,9 +35,9 @@ export const AlbumArtistCell = ({ data, value }: ICellRendererParams) => {
|
|||
{index > 0 && <Separator />}
|
||||
{item.id ? (
|
||||
<Text
|
||||
$link
|
||||
$secondary
|
||||
component={Link}
|
||||
isLink
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
|
||||
|
|
@ -48,7 +48,7 @@ export const AlbumArtistCell = ({ data, value }: ICellRendererParams) => {
|
|||
</Text>
|
||||
) : (
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ import React from 'react';
|
|||
import { generatePath } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Separator } from '/@/renderer/components/separator';
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
export const ArtistCell = ({ data, value }: ICellRendererParams) => {
|
||||
if (value === undefined) {
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Skeleton
|
||||
height="1rem"
|
||||
width="80%"
|
||||
|
|
@ -24,9 +24,9 @@ export const ArtistCell = ({ data, value }: ICellRendererParams) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
|
|
@ -35,9 +35,9 @@ export const ArtistCell = ({ data, value }: ICellRendererParams) => {
|
|||
{index > 0 && <Separator />}
|
||||
{item.id ? (
|
||||
<Text
|
||||
$link
|
||||
$secondary
|
||||
component={Link}
|
||||
isLink
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
|
||||
|
|
@ -48,7 +48,7 @@ export const ArtistCell = ({ data, value }: ICellRendererParams) => {
|
|||
</Text>
|
||||
) : (
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
.play-button {
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: var(--theme-colors-white);
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
opacity: 0.7;
|
||||
transition: scale 0.1s ease-in-out;
|
||||
|
||||
svg {
|
||||
color: var(--theme-colors-black);
|
||||
fill: var(--theme-colors-black);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-colors-white);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.list-controls-container {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
@ -1,62 +1,21 @@
|
|||
import type { UnstyledButtonProps } from '@mantine/core';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import React, { MouseEvent } from 'react';
|
||||
import { RiPlayFill } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import styles from './combined-title-cell-controls.module.css';
|
||||
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
type PlayButtonType = React.ComponentPropsWithoutRef<'button'> & UnstyledButtonProps;
|
||||
|
||||
const PlayButton = styled.button<PlayButtonType>`
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: rgb(255 255 255);
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
opacity: 0.8;
|
||||
transition: scale 0.1s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
scale: 1.1;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: rgb(0 0 0);
|
||||
stroke: rgb(0 0 0);
|
||||
}
|
||||
`;
|
||||
|
||||
const ListConverControlsContainer = styled.div`
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const ListCoverControls = ({
|
||||
className,
|
||||
context,
|
||||
itemData,
|
||||
itemType,
|
||||
uniqueId,
|
||||
}: {
|
||||
className?: string;
|
||||
context: Record<string, any>;
|
||||
itemData: any;
|
||||
itemType: LibraryItem;
|
||||
|
|
@ -66,7 +25,7 @@ export const ListCoverControls = ({
|
|||
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||
const isQueue = Boolean(context?.isQueue);
|
||||
|
||||
const handlePlay = async (e: MouseEvent<HTMLButtonElement>, playType?: Play) => {
|
||||
const handlePlay = async (e: React.MouseEvent<HTMLButtonElement>, playType?: Play) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
|
|
@ -88,12 +47,12 @@ export const ListCoverControls = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListConverControlsContainer className="card-controls">
|
||||
<PlayButton onClick={isQueue ? handlePlayFromQueue : handlePlay}>
|
||||
<RiPlayFill size={20} />
|
||||
</PlayButton>
|
||||
</ListConverControlsContainer>
|
||||
</>
|
||||
<div className={clsx(styles.listControlsContainer, className)}>
|
||||
<ActionIcon
|
||||
classNames={{ root: styles.playButton }}
|
||||
icon="mediaPlay"
|
||||
onClick={isQueue ? handlePlayFromQueue : handlePlay}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
.cell-container {
|
||||
display: grid;
|
||||
grid-template-areas: 'image info';
|
||||
grid-template-rows: 1fr;
|
||||
grid-auto-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
letter-spacing: 0.5px;
|
||||
|
||||
&:hover {
|
||||
.play-button {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.play-button {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
grid-area: image;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.metadata-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-area: info;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.metadata-wrapper > div {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.skeleton-metadata {
|
||||
height: var(--theme-font-size-md);
|
||||
}
|
||||
|
|
@ -1,67 +1,19 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import { Center } from '@mantine/core';
|
||||
import { motion } from 'framer-motion';
|
||||
import React, { useMemo } from 'react';
|
||||
import { RiAlbumFill } from 'react-icons/ri';
|
||||
import { generatePath } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { SimpleImg } from 'react-simple-img';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import styles from './combined-title-cell.module.css';
|
||||
|
||||
import { ListCoverControls } from '/@/renderer/components/virtual-table/cells/combined-title-cell-controls';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { SEPARATOR_STRING } from '/@/shared/api/utils';
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
|
||||
const CellContainer = styled(motion.div)<{ height: number }>`
|
||||
display: grid;
|
||||
grid-template-areas: 'image info';
|
||||
grid-template-rows: 1fr;
|
||||
grid-template-columns: ${(props) => props.height}px minmax(0, 1fr);
|
||||
grid-auto-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
letter-spacing: 0.5px;
|
||||
|
||||
.card-controls {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.card-controls {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ImageWrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
grid-area: image;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
const MetadataWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-area: info;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledImage = styled(SimpleImg)`
|
||||
img {
|
||||
object-fit: var(--image-fit);
|
||||
}
|
||||
`;
|
||||
|
||||
export const CombinedTitleCell = ({
|
||||
context,
|
||||
data,
|
||||
|
|
@ -76,60 +28,55 @@ export const CombinedTitleCell = ({
|
|||
|
||||
if (value === undefined) {
|
||||
return (
|
||||
<CellContainer height={node.rowHeight || 40}>
|
||||
<Skeleton>
|
||||
<ImageWrapper />
|
||||
</Skeleton>
|
||||
<MetadataWrapper>
|
||||
<Skeleton
|
||||
height="1rem"
|
||||
width="80%"
|
||||
/>
|
||||
<Skeleton
|
||||
height="1rem"
|
||||
mt="0.5rem"
|
||||
width="60%"
|
||||
/>
|
||||
</MetadataWrapper>
|
||||
</CellContainer>
|
||||
<div
|
||||
className={styles.cellContainer}
|
||||
style={{ gridTemplateColumns: `${node.rowHeight || 40}px minmax(0, 1fr)` }}
|
||||
>
|
||||
<div
|
||||
className={styles.imageWrapper}
|
||||
style={{
|
||||
height: `${(node.rowHeight || 40) - 10}px`,
|
||||
width: `${(node.rowHeight || 40) - 10}px`,
|
||||
}}
|
||||
>
|
||||
<Skeleton className={styles.image} />
|
||||
</div>
|
||||
<Skeleton
|
||||
className={styles.skeletonMetadata}
|
||||
height="1rem"
|
||||
width="80%"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<CellContainer height={node.rowHeight || 40}>
|
||||
<ImageWrapper>
|
||||
{value.imageUrl ? (
|
||||
<StyledImage
|
||||
alt="cover"
|
||||
height={(node.rowHeight || 40) - 10}
|
||||
placeholder={value.imagePlaceholderUrl || 'var(--placeholder-bg)'}
|
||||
src={value.imageUrl}
|
||||
style={{}}
|
||||
width={(node.rowHeight || 40) - 10}
|
||||
/>
|
||||
) : (
|
||||
<Center
|
||||
sx={{
|
||||
background: 'var(--placeholder-bg)',
|
||||
borderRadius: 'var(--card-default-radius)',
|
||||
height: `${(node.rowHeight || 40) - 10}px`,
|
||||
width: `${(node.rowHeight || 40) - 10}px`,
|
||||
}}
|
||||
>
|
||||
<RiAlbumFill
|
||||
color="var(--placeholder-fg)"
|
||||
size={35}
|
||||
/>
|
||||
</Center>
|
||||
)}
|
||||
<div
|
||||
className={styles.cellContainer}
|
||||
style={{ gridTemplateColumns: `${node.rowHeight || 40}px minmax(0, 1fr)` }}
|
||||
>
|
||||
<div
|
||||
className={styles.imageWrapper}
|
||||
style={{
|
||||
height: `${(node.rowHeight || 40) - 10}px`,
|
||||
width: `${(node.rowHeight || 40) - 10}px`,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
alt="cover"
|
||||
className={styles.image}
|
||||
src={value.imageUrl}
|
||||
/>
|
||||
|
||||
<ListCoverControls
|
||||
className={styles.playButton}
|
||||
context={context}
|
||||
itemData={value}
|
||||
itemType={context.itemType}
|
||||
uniqueId={data?.uniqueId}
|
||||
/>
|
||||
</ImageWrapper>
|
||||
<MetadataWrapper>
|
||||
</div>
|
||||
<div className={styles.metadataWrapper}>
|
||||
<Text
|
||||
className="current-song-child"
|
||||
overflow="hidden"
|
||||
|
|
@ -138,7 +85,7 @@ export const CombinedTitleCell = ({
|
|||
{value.name}
|
||||
</Text>
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
|
|
@ -148,12 +95,12 @@ export const CombinedTitleCell = ({
|
|||
{index > 0 ? SEPARATOR_STRING : null}
|
||||
{artist.id ? (
|
||||
<Text
|
||||
$link
|
||||
$secondary
|
||||
component={Link}
|
||||
isLink
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
sx={{ width: 'fit-content' }}
|
||||
style={{ width: 'fit-content' }}
|
||||
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
|
||||
albumArtistId: artist.id,
|
||||
})}
|
||||
|
|
@ -162,10 +109,10 @@ export const CombinedTitleCell = ({
|
|||
</Text>
|
||||
) : (
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
sx={{ width: 'fit-content' }}
|
||||
style={{ width: 'fit-content' }}
|
||||
>
|
||||
{artist.name}
|
||||
</Text>
|
||||
|
|
@ -173,10 +120,10 @@ export const CombinedTitleCell = ({
|
|||
</React.Fragment>
|
||||
))
|
||||
) : (
|
||||
<Text $secondary>—</Text>
|
||||
<Text isMuted>—</Text>
|
||||
)}
|
||||
</Text>
|
||||
</MetadataWrapper>
|
||||
</CellContainer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import { RiHeartFill, RiHeartLine } from 'react-icons/ri';
|
||||
|
||||
import { Button } from '/@/renderer/components/button';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
|
||||
export const FavoriteCell = ({ data, node, value }: ICellRendererParams) => {
|
||||
const createMutation = useCreateFavorite({});
|
||||
|
|
@ -47,21 +45,16 @@ export const FavoriteCell = ({ data, node, value }: ICellRendererParams) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<CellContainer $position="center">
|
||||
<Button
|
||||
compact
|
||||
onClick={handleToggleFavorite}
|
||||
sx={{
|
||||
svg: {
|
||||
fill: !value
|
||||
? 'var(--main-fg-secondary) !important'
|
||||
: 'var(--primary-color) !important',
|
||||
},
|
||||
<CellContainer position="center">
|
||||
<ActionIcon
|
||||
icon="favorite"
|
||||
iconProps={{
|
||||
fill: !value ? undefined : 'primary',
|
||||
}}
|
||||
onClick={handleToggleFavorite}
|
||||
size="sm"
|
||||
variant="subtle"
|
||||
>
|
||||
{!value ? <RiHeartLine size="1.3em" /> : <RiHeartFill size="1.3em" />}
|
||||
</Button>
|
||||
/>
|
||||
</CellContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
.container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
|
@ -1,19 +1,12 @@
|
|||
import { ICellRendererParams } from '@ag-grid-community/core';
|
||||
import { Group } from '@mantine/core';
|
||||
import { useState } from 'react';
|
||||
import { RiCheckboxBlankLine, RiCheckboxLine } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Button } from '/@/renderer/components/button';
|
||||
import { Paper } from '/@/renderer/components/paper';
|
||||
import styles from './full-width-disc-cell.module.css';
|
||||
|
||||
import { getNodesByDiscNumber, setNodeSelection } from '/@/renderer/components/virtual-table/utils';
|
||||
|
||||
const Container = styled(Paper)`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid transparent;
|
||||
`;
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
|
||||
export const FullWidthDiscCell = ({ api, data, node }: ICellRendererParams) => {
|
||||
const [isSelected, setIsSelected] = useState(false);
|
||||
|
|
@ -31,21 +24,20 @@ export const FullWidthDiscCell = ({ api, data, node }: ICellRendererParams) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className={styles.container}>
|
||||
<Group
|
||||
position="apart"
|
||||
justify="space-between"
|
||||
w="100%"
|
||||
>
|
||||
<Button
|
||||
compact
|
||||
leftIcon={isSelected ? <RiCheckboxLine /> : <RiCheckboxBlankLine />}
|
||||
leftSection={isSelected ? <Icon icon="squareCheck" /> : <Icon icon="square" />}
|
||||
onClick={handleToggleDiscNodes}
|
||||
size="md"
|
||||
size="compact-md"
|
||||
variant="subtle"
|
||||
>
|
||||
{data.name}
|
||||
</Button>
|
||||
</Group>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
.cell-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.cell-container.right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.cell-container.center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cell-container.left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
|
@ -1,24 +1,12 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import styles from './generic-cell.module.css';
|
||||
|
||||
export const CellContainer = styled.div<{ $position?: 'center' | 'left' | 'right' }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: ${(props) =>
|
||||
props.$position === 'right'
|
||||
? 'flex-end'
|
||||
: props.$position === 'center'
|
||||
? 'center'
|
||||
: 'flex-start'};
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
letter-spacing: 0.5px;
|
||||
`;
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
type Options = {
|
||||
array?: boolean;
|
||||
|
|
@ -36,7 +24,7 @@ export const GenericCell = (
|
|||
|
||||
if (value === undefined) {
|
||||
return (
|
||||
<CellContainer $position={position || 'left'}>
|
||||
<CellContainer position={position || 'left'}>
|
||||
<Skeleton
|
||||
height="1rem"
|
||||
width="80%"
|
||||
|
|
@ -46,12 +34,12 @@ export const GenericCell = (
|
|||
}
|
||||
|
||||
return (
|
||||
<CellContainer $position={position || 'left'}>
|
||||
<CellContainer position={position || 'left'}>
|
||||
{isLink ? (
|
||||
<Text
|
||||
$link={isLink}
|
||||
$secondary={!primary}
|
||||
component={Link}
|
||||
isLink={isLink}
|
||||
isMuted={!primary}
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
to={displayedValue.link}
|
||||
|
|
@ -60,8 +48,8 @@ export const GenericCell = (
|
|||
</Text>
|
||||
) : (
|
||||
<Text
|
||||
$noSelect={false}
|
||||
$secondary={!primary}
|
||||
isMuted={!primary}
|
||||
isNoSelect={false}
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
|
|
@ -71,3 +59,24 @@ export const GenericCell = (
|
|||
</CellContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const CellContainer = ({
|
||||
children,
|
||||
position,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
position: 'center' | 'left' | 'right';
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx({
|
||||
[styles.cellContainer]: true,
|
||||
[styles.center]: position === 'center',
|
||||
[styles.left]: position === 'left' || !position,
|
||||
[styles.right]: position === 'right',
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@ import type { ICellRendererParams } from '@ag-grid-community/core';
|
|||
import React from 'react';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
|
||||
import { Separator } from '/@/renderer/components/separator';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
||||
import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
export const GenreCell = ({ data, value }: ICellRendererParams) => {
|
||||
const genrePath = useGenreRoute();
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
|
|
@ -22,9 +22,9 @@ export const GenreCell = ({ data, value }: ICellRendererParams) => {
|
|||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && <Separator />}
|
||||
<Text
|
||||
$link
|
||||
$secondary
|
||||
component={Link}
|
||||
isLink
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
to={generatePath(genrePath, { genreId: item.id })}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import type { ICellRendererParams } from '@ag-grid-community/core';
|
|||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { replaceURLWithHTMLLinks } from '/@/renderer/utils/linkify';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
export const NoteCell = ({ value }: ICellRendererParams) => {
|
||||
const formattedValue = useMemo(() => {
|
||||
|
|
@ -18,7 +18,7 @@ export const NoteCell = ({ value }: ICellRendererParams) => {
|
|||
|
||||
if (value === undefined) {
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Skeleton
|
||||
height="1rem"
|
||||
width="80%"
|
||||
|
|
@ -28,9 +28,9 @@ export const NoteCell = ({ value }: ICellRendererParams) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
>
|
||||
{formattedValue}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import { Rating } from '/@/renderer/components/rating';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { useSetRating } from '/@/renderer/features/shared';
|
||||
import { Rating } from '/@/shared/components/rating/rating';
|
||||
|
||||
export const RatingCell = ({ node, value }: ICellRendererParams) => {
|
||||
const updateRatingMutation = useSetRating({});
|
||||
|
|
@ -25,7 +25,7 @@ export const RatingCell = ({ node, value }: ICellRendererParams) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<CellContainer $position="center">
|
||||
<CellContainer position="center">
|
||||
<Rating
|
||||
onChange={handleUpdateRating}
|
||||
size="xs"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import { RiPlayFill } from 'react-icons/ri';
|
||||
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
// const AnimatedSvg = () => {
|
||||
// return (
|
||||
|
|
@ -14,7 +13,7 @@ import { CellContainer } from '/@/renderer/components/virtual-table/cells/generi
|
|||
// >
|
||||
// <g>
|
||||
// <rect
|
||||
// fill="var(--primary-color)"
|
||||
// fill="var(--theme-colors-primary-filled)"
|
||||
// height="80"
|
||||
// id="bar-1"
|
||||
// width="12"
|
||||
|
|
@ -33,7 +32,7 @@ import { CellContainer } from '/@/renderer/components/virtual-table/cells/generi
|
|||
// />
|
||||
// </rect>
|
||||
// <rect
|
||||
// fill="var(--primary-color)"
|
||||
// fill="var(--theme-colors-primary-filled)"
|
||||
// height="80"
|
||||
// id="bar-2"
|
||||
// width="12"
|
||||
|
|
@ -52,7 +51,7 @@ import { CellContainer } from '/@/renderer/components/virtual-table/cells/generi
|
|||
// />
|
||||
// </rect>
|
||||
// <rect
|
||||
// fill="var(--primary-color)"
|
||||
// fill="var(--theme-colors-primary-filled)"
|
||||
// height="80"
|
||||
// id="bar-3"
|
||||
// width="12"
|
||||
|
|
@ -71,7 +70,7 @@ import { CellContainer } from '/@/renderer/components/virtual-table/cells/generi
|
|||
// />
|
||||
// </rect>
|
||||
// <rect
|
||||
// fill="var(--primary-color)"
|
||||
// fill="var(--theme-colors-primary-filled)"
|
||||
// height="80"
|
||||
// id="bar-4"
|
||||
// width="12"
|
||||
|
|
@ -143,23 +142,28 @@ export const RowIndexCell = ({ eGridCell, value }: ICellRendererParams) => {
|
|||
classList.contains('current-song-cell') || classList.contains('current-playlist-song-cell');
|
||||
|
||||
return (
|
||||
<CellContainer $position="right">
|
||||
{isPlaying &&
|
||||
(isCurrentSong ? (
|
||||
<RiPlayFill
|
||||
color="var(--primary-color)"
|
||||
size="1.2rem"
|
||||
/>
|
||||
) : null)}
|
||||
<Text
|
||||
$secondary
|
||||
align="right"
|
||||
className="current-song-child current-song-index"
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
>
|
||||
{value}
|
||||
</Text>
|
||||
<CellContainer position="right">
|
||||
{isPlaying && isCurrentSong ? (
|
||||
<Icon
|
||||
fill="primary"
|
||||
icon="mediaPlay"
|
||||
/>
|
||||
) : isCurrentSong ? (
|
||||
<Icon
|
||||
fill="primary"
|
||||
icon="mediaPause"
|
||||
/>
|
||||
) : (
|
||||
<Text
|
||||
className="current-song-child current-song-index"
|
||||
isMuted
|
||||
overflow="hidden"
|
||||
size="md"
|
||||
style={{ textAlign: 'right' }}
|
||||
>
|
||||
{value}
|
||||
</Text>
|
||||
)}
|
||||
</CellContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
export const TitleCell = ({ value }: ICellRendererParams) => {
|
||||
if (value === undefined) {
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Skeleton
|
||||
height="1rem"
|
||||
width="80%"
|
||||
|
|
@ -17,7 +17,7 @@ export const TitleCell = ({ value }: ICellRendererParams) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<CellContainer $position="left">
|
||||
<CellContainer position="left">
|
||||
<Text
|
||||
className="current-song-child"
|
||||
overflow="hidden"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
import type { IHeaderParams } from '@ag-grid-community/core';
|
||||
|
||||
import { FiClock } from 'react-icons/fi';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
|
||||
export interface ICustomHeaderParams extends IHeaderParams {
|
||||
menuIcon: string;
|
||||
}
|
||||
|
||||
export const DurationHeader = () => {
|
||||
return <FiClock size={15} />;
|
||||
return (
|
||||
<Icon
|
||||
icon="duration"
|
||||
size="sm"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
.header-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.header-wrapper.right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.header-wrapper.center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header-wrapper.left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.header-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-weight: 500;
|
||||
line-height: inherit;
|
||||
color: var(--theme-colors-foreground);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.header-text.right {
|
||||
text-align: flex-end;
|
||||
}
|
||||
|
||||
.header-text.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header-text.left {
|
||||
text-align: flex-start;
|
||||
}
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
import type { IHeaderParams } from '@ag-grid-community/core';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
import { AiOutlineNumber } from 'react-icons/ai';
|
||||
import { FiClock } from 'react-icons/fi';
|
||||
import { RiHeartLine, RiMoreFill, RiStarLine } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { _Text } from '/@/renderer/components/text';
|
||||
import styles from './generic-table-header.module.css';
|
||||
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
|
||||
type Options = {
|
||||
children?: ReactNode;
|
||||
|
|
@ -16,63 +15,35 @@ type Options = {
|
|||
|
||||
type Presets = 'actions' | 'duration' | 'rowIndex' | 'userFavorite' | 'userRating';
|
||||
|
||||
export const HeaderWrapper = styled.div<{ $position: Options['position'] }>`
|
||||
display: flex;
|
||||
justify-content: ${(props) =>
|
||||
props.$position === 'right'
|
||||
? 'flex-end'
|
||||
: props.$position === 'center'
|
||||
? 'center'
|
||||
: 'flex-start'};
|
||||
width: 100%;
|
||||
font-family: var(--content-font-family);
|
||||
text-transform: uppercase;
|
||||
`;
|
||||
|
||||
const HeaderText = styled(_Text)<{ $position: Options['position'] }>`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-weight: 500;
|
||||
line-height: inherit;
|
||||
color: var(--ag-header-foreground-color);
|
||||
text-align: ${(props) =>
|
||||
props.$position === 'right'
|
||||
? 'flex-end'
|
||||
: props.$position === 'center'
|
||||
? 'center'
|
||||
: 'flex-start'};
|
||||
text-transform: uppercase;
|
||||
`;
|
||||
|
||||
const headerPresets = {
|
||||
actions: (
|
||||
<RiMoreFill
|
||||
color="var(--ag-header-foreground-color)"
|
||||
size="1em"
|
||||
<Icon
|
||||
icon="ellipsisHorizontal"
|
||||
size="sm"
|
||||
/>
|
||||
),
|
||||
duration: (
|
||||
<FiClock
|
||||
color="var(--ag-header-foreground-color)"
|
||||
size="1em"
|
||||
<Icon
|
||||
icon="duration"
|
||||
size="sm"
|
||||
/>
|
||||
),
|
||||
rowIndex: (
|
||||
<AiOutlineNumber
|
||||
color="var(--ag-header-foreground-color)"
|
||||
size="1em"
|
||||
<Icon
|
||||
icon="hash"
|
||||
size="sm"
|
||||
/>
|
||||
),
|
||||
userFavorite: (
|
||||
<RiHeartLine
|
||||
color="var(--ag-header-foreground-color)"
|
||||
size="1em"
|
||||
<Icon
|
||||
icon="favorite"
|
||||
size="sm"
|
||||
/>
|
||||
),
|
||||
userRating: (
|
||||
<RiStarLine
|
||||
color="var(--ag-header-foreground-color)"
|
||||
size="1em"
|
||||
<Icon
|
||||
icon="star"
|
||||
size="sm"
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
|
@ -82,18 +53,18 @@ export const GenericTableHeader = (
|
|||
{ children, position, preset }: Options,
|
||||
) => {
|
||||
if (preset) {
|
||||
return <HeaderWrapper $position={position}>{headerPresets[preset]}</HeaderWrapper>;
|
||||
return (
|
||||
<div className={clsx(styles.headerWrapper, styles[position ?? 'left'])}>
|
||||
{headerPresets[preset]}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<HeaderWrapper $position={position}>
|
||||
<HeaderText
|
||||
$position={position}
|
||||
overflow="hidden"
|
||||
weight={500}
|
||||
>
|
||||
<div className={clsx(styles.headerWrapper, styles[position ?? 'left'])}>
|
||||
<div className={clsx(styles.headerText, styles[position ?? 'left'])}>
|
||||
{children || displayName}
|
||||
</HeaderText>
|
||||
</HeaderWrapper>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useInView } from 'framer-motion';
|
||||
import { useInView } from 'motion/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import { useWindowSettings } from '/@/renderer/store/settings.store';
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
|
|||
|
||||
import { AgGridReact } from '@ag-grid-community/react';
|
||||
import { useClickOutside, useMergedRef } from '@mantine/hooks';
|
||||
import clsx from 'clsx';
|
||||
import formatDuration from 'format-duration';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import { AnimatePresence } from 'motion/react';
|
||||
import { forwardRef, Ref, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { generatePath } from 'react-router';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import styles from './virtual-table.module.css';
|
||||
|
||||
import i18n from '/@/i18n/i18n';
|
||||
import { ActionsCell } from '/@/renderer/components/virtual-table/cells/actions-cell';
|
||||
|
|
@ -57,18 +59,18 @@ export * from './table-config-dropdown';
|
|||
export * from './table-pagination';
|
||||
export * from './utils';
|
||||
|
||||
const TableWrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`;
|
||||
// const TableWrapper = styled.div`
|
||||
// position: relative;
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// `;
|
||||
|
||||
const DummyHeader = styled.div<{ height?: number }>`
|
||||
position: absolute;
|
||||
height: ${({ height }) => height || 36}px;
|
||||
`;
|
||||
// const DummyHeader = styled.div<{ height?: number }>`
|
||||
// position: absolute;
|
||||
// height: ${({ height }) => height || 36}px;
|
||||
// `;
|
||||
|
||||
const tableColumns: { [key: string]: ColDef } = {
|
||||
actions: {
|
||||
|
|
@ -593,15 +595,20 @@ export const VirtualTable = forwardRef(
|
|||
const mergedWrapperRef = useMergedRef(deselectRef, tableContainerRef);
|
||||
|
||||
return (
|
||||
<TableWrapper
|
||||
className={
|
||||
<div
|
||||
className={clsx(
|
||||
styles.tableWrapper,
|
||||
transparentHeader
|
||||
? 'ag-theme-alpine-dark ag-header-transparent'
|
||||
: 'ag-theme-alpine-dark'
|
||||
}
|
||||
: 'ag-theme-alpine-dark',
|
||||
)}
|
||||
ref={mergedWrapperRef}
|
||||
>
|
||||
<DummyHeader ref={tableHeaderRef} />
|
||||
<div
|
||||
className={styles.dummyHeader}
|
||||
ref={tableHeaderRef}
|
||||
style={{ height: rest.headerHeight ?? 36 }}
|
||||
/>
|
||||
<AgGridReact
|
||||
animateRows
|
||||
blockLoadDebounceMillis={200}
|
||||
|
|
@ -639,7 +646,7 @@ export const VirtualTable = forwardRef(
|
|||
/>
|
||||
</AnimatePresence>
|
||||
)}
|
||||
</TableWrapper>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import type { ChangeEvent } from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import i18n from '/@/i18n/i18n';
|
||||
import { Option } from '/@/renderer/components/option';
|
||||
import { MultiSelect } from '/@/renderer/components/select';
|
||||
import { Slider } from '/@/renderer/components/slider';
|
||||
import { Switch } from '/@/renderer/components/switch';
|
||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { MultiSelect } from '/@/shared/components/multi-select/multi-select';
|
||||
import { Option } from '/@/shared/components/option/option';
|
||||
import { Slider } from '/@/shared/components/slider/slider';
|
||||
import { Switch } from '/@/shared/components/switch/switch';
|
||||
import { TableColumn, TableType } from '/@/shared/types/types';
|
||||
|
||||
export const SONG_TABLE_COLUMNS = [
|
||||
|
|
@ -292,7 +292,7 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
|
|||
const { setSettings } = useSettingsStoreActions();
|
||||
const tableConfig = useSettingsStore((state) => state.tables);
|
||||
|
||||
const handleAddOrRemoveColumns = (values: TableColumn[]) => {
|
||||
const handleAddOrRemoveColumns = (values: string[]) => {
|
||||
const existingColumns = tableConfig[type].columns;
|
||||
|
||||
if (values.length === 0) {
|
||||
|
|
@ -421,8 +421,8 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
|
|||
clearable
|
||||
data={SONG_TABLE_COLUMNS}
|
||||
defaultValue={tableConfig[type]?.columns.map((column) => column.column)}
|
||||
dropdownPosition="bottom"
|
||||
onChange={handleAddOrRemoveColumns}
|
||||
variant="filled"
|
||||
width={300}
|
||||
/>
|
||||
</Option.Control>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
||||
|
||||
import { Group } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { MutableRefObject } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RiHashtag } from 'react-icons/ri';
|
||||
|
||||
import { Button } from '/@/renderer/components/button';
|
||||
import { NumberInput } from '/@/renderer/components/input';
|
||||
import { MotionFlex } from '/@/renderer/components/motion';
|
||||
import { Pagination } from '/@/renderer/components/pagination';
|
||||
import { Popover } from '/@/renderer/components/popover';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { useContainerQuery } from '/@/renderer/hooks';
|
||||
import { ListKey } from '/@/renderer/store';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { NumberInput } from '/@/shared/components/number-input/number-input';
|
||||
import { Pagination } from '/@/shared/components/pagination/pagination';
|
||||
import { Popover } from '/@/shared/components/popover/popover';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { TablePagination as TablePaginationType } from '/@/shared/types/types';
|
||||
|
||||
interface TablePaginationProps {
|
||||
|
|
@ -32,7 +31,6 @@ export const TablePagination = ({
|
|||
setPagination,
|
||||
tableRef,
|
||||
}: TablePaginationProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [isGoToPageOpen, handlers] = useDisclosure(false);
|
||||
const containerQuery = useContainerQuery();
|
||||
|
||||
|
|
@ -71,19 +69,15 @@ export const TablePagination = ({
|
|||
currentPageMaxIndex > pagination.totalItems ? pagination.totalItems : currentPageMaxIndex;
|
||||
|
||||
return (
|
||||
<MotionFlex
|
||||
<Flex
|
||||
align="center"
|
||||
animate={{ y: 0 }}
|
||||
exit={{ y: 50 }}
|
||||
initial={{ y: 50 }}
|
||||
justify="space-between"
|
||||
layout
|
||||
p="1rem"
|
||||
ref={containerQuery.ref}
|
||||
sx={{ borderTop: '1px solid var(--generic-border-color)' }}
|
||||
style={{ borderTop: '1px solid var(--theme-generic-border-color)' }}
|
||||
>
|
||||
<Text
|
||||
$secondary
|
||||
isMuted
|
||||
size="md"
|
||||
>
|
||||
{containerQuery.isMd ? (
|
||||
|
|
@ -104,9 +98,9 @@ export const TablePagination = ({
|
|||
)}
|
||||
</Text>
|
||||
<Group
|
||||
noWrap
|
||||
gap="sm"
|
||||
ref={containerQuery.ref}
|
||||
spacing="sm"
|
||||
wrap="nowrap"
|
||||
>
|
||||
<Popover
|
||||
onClose={() => handlers.close()}
|
||||
|
|
@ -115,18 +109,13 @@ export const TablePagination = ({
|
|||
trapFocus
|
||||
>
|
||||
<Popover.Target>
|
||||
<Button
|
||||
<ActionIcon
|
||||
icon="hash"
|
||||
onClick={() => handlers.toggle()}
|
||||
radius="sm"
|
||||
size="sm"
|
||||
sx={{ height: '26px', padding: '0', width: '26px' }}
|
||||
tooltip={{
|
||||
label: t('action.goToPage', { postProcess: 'sentenceCase' }),
|
||||
}}
|
||||
variant="default"
|
||||
>
|
||||
<RiHashtag size={15} />
|
||||
</Button>
|
||||
style={{ height: '26px', padding: '0', width: '26px' }}
|
||||
/>
|
||||
</Popover.Target>
|
||||
<Popover.Dropdown>
|
||||
<form onSubmit={handleGoSubmit}>
|
||||
|
|
@ -149,9 +138,7 @@ export const TablePagination = ({
|
|||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
<Pagination
|
||||
$hideDividers={!containerQuery.isSm}
|
||||
boundaries={1}
|
||||
noWrap
|
||||
onChange={handlePagination}
|
||||
radius="sm"
|
||||
siblings={containerQuery.isMd ? 2 : containerQuery.isSm ? 1 : 0}
|
||||
|
|
@ -159,6 +146,6 @@ export const TablePagination = ({
|
|||
value={pagination.currentPage + 1}
|
||||
/>
|
||||
</Group>
|
||||
</MotionFlex>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
.table-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.dummy-header {
|
||||
position: absolute;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue