mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
add draggable table column resize
This commit is contained in:
@@ -6,12 +6,18 @@ import { ItemListStateItemWithRequiredProperties } from '/@/renderer/components/
|
|||||||
import { DefaultItemControlProps, ItemControls } from '/@/renderer/components/item-list/types';
|
import { DefaultItemControlProps, ItemControls } from '/@/renderer/components/item-list/types';
|
||||||
import { usePlayerContext } from '/@/renderer/features/player/context/player-context';
|
import { usePlayerContext } from '/@/renderer/features/player/context/player-context';
|
||||||
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
|
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
|
||||||
import { Play } from '/@/shared/types/types';
|
import { Play, TableColumn } from '/@/shared/types/types';
|
||||||
|
|
||||||
export const useDefaultItemListControls = () => {
|
interface UseDefaultItemListControlsArgs {
|
||||||
|
onColumnResized?: (columnId: TableColumn, width: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDefaultItemListControls = (args?: UseDefaultItemListControlsArgs) => {
|
||||||
const player = usePlayerContext();
|
const player = usePlayerContext();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const { onColumnResized } = args || {};
|
||||||
|
|
||||||
const controls: ItemControls = useMemo(() => {
|
const controls: ItemControls = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
onClick: ({ event, internalState, item }: DefaultItemControlProps) => {
|
onClick: ({ event, internalState, item }: DefaultItemControlProps) => {
|
||||||
@@ -147,6 +153,10 @@ export const useDefaultItemListControls = () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onColumnResized: ({ columnId, width }: { columnId: TableColumn; width: number }) => {
|
||||||
|
onColumnResized?.(columnId, width);
|
||||||
|
},
|
||||||
|
|
||||||
onDoubleClick: ({ internalState, item, itemType }: DefaultItemControlProps) => {
|
onDoubleClick: ({ internalState, item, itemType }: DefaultItemControlProps) => {
|
||||||
if (!item || !internalState) {
|
if (!item || !internalState) {
|
||||||
return;
|
return;
|
||||||
@@ -239,7 +249,7 @@ export const useDefaultItemListControls = () => {
|
|||||||
player.setRating(item._serverId, [item.id], itemType, newRating);
|
player.setRating(item._serverId, [item.id], itemType, newRating);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [player, navigate]);
|
}, [onColumnResized, navigate, player]);
|
||||||
|
|
||||||
return controls;
|
return controls;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store';
|
||||||
|
import { ItemListKey, TableColumn } from '/@/shared/types/types';
|
||||||
|
|
||||||
|
interface UseItemListColumnResizeProps {
|
||||||
|
itemListKey: ItemListKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useItemListColumnResize = ({ itemListKey }: UseItemListColumnResizeProps) => {
|
||||||
|
const { setList } = useSettingsStoreActions();
|
||||||
|
const columns = useSettingsStore((state) => state.lists[itemListKey]?.table.columns);
|
||||||
|
|
||||||
|
const handleColumnResized = useCallback(
|
||||||
|
(columnId: TableColumn, width: number) => {
|
||||||
|
if (!columns) return;
|
||||||
|
|
||||||
|
const updatedColumns = columns.map((column) =>
|
||||||
|
column.id === columnId ? { ...column, width } : column,
|
||||||
|
);
|
||||||
|
|
||||||
|
setList(itemListKey, {
|
||||||
|
table: {
|
||||||
|
columns: updatedColumns,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[columns, itemListKey, setList],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { handleColumnResized };
|
||||||
|
};
|
||||||
@@ -167,6 +167,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.header-container {
|
.header-container {
|
||||||
|
position: relative;
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,3 +263,58 @@
|
|||||||
.container.data-row.row-hovered :global(.hide-on-hover) {
|
.container.data-row.row-hovered :global(.hide-on-hover) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
bottom: 8px;
|
||||||
|
z-index: 10;
|
||||||
|
width: 8px;
|
||||||
|
margin-right: -4px;
|
||||||
|
cursor: col-resize;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 2px;
|
||||||
|
content: '';
|
||||||
|
background-color: transparent;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container:hover .resize-handle {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container:hover .resize-handle::before {
|
||||||
|
background-color: var(--theme-colors-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle-left {
|
||||||
|
left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle-left::before {
|
||||||
|
right: auto;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle-right {
|
||||||
|
right: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle-dragging {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMergedRef } from '@mantine/hooks';
|
import { useMergedRef } from '@mantine/hooks';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React, { CSSProperties, ReactNode, useEffect, useRef } from 'react';
|
import React, { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react';
|
||||||
import { CellComponentProps } from 'react-window-v2';
|
import { CellComponentProps } from 'react-window-v2';
|
||||||
|
|
||||||
import styles from './item-table-list-column.module.css';
|
import styles from './item-table-list-column.module.css';
|
||||||
@@ -716,6 +716,82 @@ export const TableColumnContainer = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface ColumnResizeHandleProps {
|
||||||
|
columnId: TableColumn;
|
||||||
|
initialWidth: number;
|
||||||
|
onResize: (columnId: TableColumn, width: number) => void;
|
||||||
|
side: 'left' | 'right';
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColumnResizeHandle = ({
|
||||||
|
columnId,
|
||||||
|
initialWidth,
|
||||||
|
onResize,
|
||||||
|
side,
|
||||||
|
}: ColumnResizeHandleProps) => {
|
||||||
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
const handleRef = useRef<HTMLDivElement>(null);
|
||||||
|
const startWidthRef = useRef<number>(initialWidth);
|
||||||
|
const startXRef = useRef<number>(0);
|
||||||
|
const finalWidthRef = useRef<number>(initialWidth);
|
||||||
|
|
||||||
|
// Update the ref when initialWidth changes (but not during drag)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isDragging) {
|
||||||
|
startWidthRef.current = initialWidth;
|
||||||
|
}
|
||||||
|
}, [initialWidth, isDragging]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isDragging) return;
|
||||||
|
|
||||||
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
|
const deltaX = event.clientX - startXRef.current;
|
||||||
|
const newWidth = Math.min(Math.max(10, startWidthRef.current + deltaX), 1000);
|
||||||
|
finalWidthRef.current = newWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
setIsDragging(false);
|
||||||
|
document.body.style.cursor = '';
|
||||||
|
document.body.style.userSelect = '';
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove);
|
||||||
|
document.removeEventListener('mouseup', handleMouseUp);
|
||||||
|
onResize(columnId, finalWidthRef.current);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
|
document.addEventListener('mouseup', handleMouseUp);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove);
|
||||||
|
document.removeEventListener('mouseup', handleMouseUp);
|
||||||
|
};
|
||||||
|
}, [isDragging, columnId, onResize]);
|
||||||
|
|
||||||
|
const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
setIsDragging(true);
|
||||||
|
startWidthRef.current = initialWidth;
|
||||||
|
startXRef.current = event.clientX;
|
||||||
|
document.body.style.cursor = 'col-resize';
|
||||||
|
document.body.style.userSelect = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(styles.resizeHandle, {
|
||||||
|
[styles.resizeHandleDragging]: isDragging,
|
||||||
|
[styles.resizeHandleLeft]: side === 'left',
|
||||||
|
[styles.resizeHandleRight]: side === 'right',
|
||||||
|
})}
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
ref={handleRef}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const TableColumnHeaderContainer = (
|
export const TableColumnHeaderContainer = (
|
||||||
props: ItemTableListColumn & {
|
props: ItemTableListColumn & {
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -724,6 +800,14 @@ export const TableColumnHeaderContainer = (
|
|||||||
type: TableColumn;
|
type: TableColumn;
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
|
const columnConfig = props.columns[props.columnIndex];
|
||||||
|
// Use the actual rendered width from style if available, otherwise fall back to config width
|
||||||
|
const currentWidth = (props.style?.width as number | undefined) || columnConfig.width;
|
||||||
|
|
||||||
|
const handleResize = (columnId: TableColumn, width: number) => {
|
||||||
|
props.controls.onColumnResized?.({ columnId, width });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
className={clsx(styles.container, styles.headerContainer, props.containerClassName, {
|
className={clsx(styles.container, styles.headerContainer, props.containerClassName, {
|
||||||
@@ -745,6 +829,14 @@ export const TableColumnHeaderContainer = (
|
|||||||
>
|
>
|
||||||
{columnLabelMap[props.type]}
|
{columnLabelMap[props.type]}
|
||||||
</Text>
|
</Text>
|
||||||
|
{!columnConfig.autoSize && props.enableColumnResize && (
|
||||||
|
<ColumnResizeHandle
|
||||||
|
columnId={props.type}
|
||||||
|
initialWidth={currentWidth}
|
||||||
|
onResize={handleResize}
|
||||||
|
side="right"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import {
|
|||||||
usePlayerContext,
|
usePlayerContext,
|
||||||
} from '/@/renderer/features/player/context/player-context';
|
} from '/@/renderer/features/player/context/player-context';
|
||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
|
import { TableColumn } from '/@/shared/types/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type guard to check if an item has the required properties (id and serverId)
|
* Type guard to check if an item has the required properties (id and serverId)
|
||||||
@@ -89,6 +90,7 @@ interface VirtualizedTableGridProps {
|
|||||||
controls: ItemControls;
|
controls: ItemControls;
|
||||||
data: unknown[];
|
data: unknown[];
|
||||||
enableAlternateRowColors: boolean;
|
enableAlternateRowColors: boolean;
|
||||||
|
enableColumnResize: boolean;
|
||||||
enableDrag?: boolean;
|
enableDrag?: boolean;
|
||||||
enableExpansion: boolean;
|
enableExpansion: boolean;
|
||||||
enableHeader: boolean;
|
enableHeader: boolean;
|
||||||
@@ -126,6 +128,7 @@ const VirtualizedTableGrid = React.memo(
|
|||||||
controls,
|
controls,
|
||||||
data,
|
data,
|
||||||
enableAlternateRowColors,
|
enableAlternateRowColors,
|
||||||
|
enableColumnResize,
|
||||||
enableDrag,
|
enableDrag,
|
||||||
enableExpansion,
|
enableExpansion,
|
||||||
enableHeader,
|
enableHeader,
|
||||||
@@ -166,6 +169,7 @@ const VirtualizedTableGrid = React.memo(
|
|||||||
controls,
|
controls,
|
||||||
data: enableHeader ? [null, ...data] : data,
|
data: enableHeader ? [null, ...data] : data,
|
||||||
enableAlternateRowColors,
|
enableAlternateRowColors,
|
||||||
|
enableColumnResize,
|
||||||
enableDrag,
|
enableDrag,
|
||||||
enableExpansion,
|
enableExpansion,
|
||||||
enableHeader,
|
enableHeader,
|
||||||
@@ -187,6 +191,7 @@ const VirtualizedTableGrid = React.memo(
|
|||||||
enableHeader,
|
enableHeader,
|
||||||
data,
|
data,
|
||||||
enableAlternateRowColors,
|
enableAlternateRowColors,
|
||||||
|
enableColumnResize,
|
||||||
enableDrag,
|
enableDrag,
|
||||||
enableExpansion,
|
enableExpansion,
|
||||||
enableHorizontalBorders,
|
enableHorizontalBorders,
|
||||||
@@ -470,6 +475,7 @@ export interface TableItemProps {
|
|||||||
controls: ItemControls;
|
controls: ItemControls;
|
||||||
data: ItemTableListProps['data'];
|
data: ItemTableListProps['data'];
|
||||||
enableAlternateRowColors?: ItemTableListProps['enableAlternateRowColors'];
|
enableAlternateRowColors?: ItemTableListProps['enableAlternateRowColors'];
|
||||||
|
enableColumnResize?: boolean;
|
||||||
enableDrag?: ItemTableListProps['enableDrag'];
|
enableDrag?: ItemTableListProps['enableDrag'];
|
||||||
enableExpansion?: ItemTableListProps['enableExpansion'];
|
enableExpansion?: ItemTableListProps['enableExpansion'];
|
||||||
enableHeader?: ItemTableListProps['enableHeader'];
|
enableHeader?: ItemTableListProps['enableHeader'];
|
||||||
@@ -509,6 +515,7 @@ interface ItemTableListProps {
|
|||||||
type: 'index' | 'offset';
|
type: 'index' | 'offset';
|
||||||
};
|
};
|
||||||
itemType: LibraryItem;
|
itemType: LibraryItem;
|
||||||
|
onColumnResized?: (columnId: TableColumn, width: number) => void;
|
||||||
onRangeChanged?: (range: { startIndex: number; stopIndex: number }) => void;
|
onRangeChanged?: (range: { startIndex: number; stopIndex: number }) => void;
|
||||||
onScrollEnd?: (offset: number, internalState: ItemListStateActions) => void;
|
onScrollEnd?: (offset: number, internalState: ItemListStateActions) => void;
|
||||||
ref?: Ref<ItemListHandle>;
|
ref?: Ref<ItemListHandle>;
|
||||||
@@ -535,6 +542,7 @@ export const ItemTableList = ({
|
|||||||
headerHeight = 40,
|
headerHeight = 40,
|
||||||
initialTop,
|
initialTop,
|
||||||
itemType,
|
itemType,
|
||||||
|
onColumnResized,
|
||||||
onRangeChanged,
|
onRangeChanged,
|
||||||
onScrollEnd,
|
onScrollEnd,
|
||||||
ref,
|
ref,
|
||||||
@@ -1363,7 +1371,9 @@ export const ItemTableList = ({
|
|||||||
handleRef.current = imperativeHandle;
|
handleRef.current = imperativeHandle;
|
||||||
}, [imperativeHandle]);
|
}, [imperativeHandle]);
|
||||||
|
|
||||||
const controls = useDefaultItemListControls();
|
const controls = useDefaultItemListControls({
|
||||||
|
onColumnResized,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -1380,6 +1390,7 @@ export const ItemTableList = ({
|
|||||||
controls={controls}
|
controls={controls}
|
||||||
data={data}
|
data={data}
|
||||||
enableAlternateRowColors={enableAlternateRowColors}
|
enableAlternateRowColors={enableAlternateRowColors}
|
||||||
|
enableColumnResize={!!onColumnResized}
|
||||||
enableDrag={enableDrag}
|
enableDrag={enableDrag}
|
||||||
enableExpansion={enableExpansion}
|
enableExpansion={enableExpansion}
|
||||||
enableHeader={enableHeader}
|
enableHeader={enableHeader}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface DefaultItemControlProps {
|
|||||||
|
|
||||||
export interface ItemControls {
|
export interface ItemControls {
|
||||||
onClick?: ({ internalState, item, itemType }: DefaultItemControlProps) => void;
|
onClick?: ({ internalState, item, itemType }: DefaultItemControlProps) => void;
|
||||||
|
onColumnResized?: ({ columnId, width }: { columnId: TableColumn; width: number }) => void;
|
||||||
onDoubleClick?: ({ internalState, item, itemType }: DefaultItemControlProps) => void;
|
onDoubleClick?: ({ internalState, item, itemType }: DefaultItemControlProps) => void;
|
||||||
onExpand?: ({ internalState, item, itemType }: DefaultItemControlProps) => void;
|
onExpand?: ({ internalState, item, itemType }: DefaultItemControlProps) => void;
|
||||||
onFavorite?: ({
|
onFavorite?: ({
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
||||||
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||||
@@ -60,6 +61,10 @@ export const AlbumListInfiniteTable = forwardRef<any, AlbumListInfiniteTableProp
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.ALBUM,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemTableList
|
<ItemTableList
|
||||||
autoFitColumns={autoFitColumns}
|
autoFitColumns={autoFitColumns}
|
||||||
@@ -76,6 +81,7 @@ export const AlbumListInfiniteTable = forwardRef<any, AlbumListInfiniteTableProp
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.ALBUM}
|
itemType={LibraryItem.ALBUM}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onRangeChanged={onRangeChanged}
|
onRangeChanged={onRangeChanged}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
||||||
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
||||||
@@ -16,6 +17,7 @@ import {
|
|||||||
LibraryItem,
|
LibraryItem,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
} from '/@/shared/types/domain-types';
|
} from '/@/shared/types/domain-types';
|
||||||
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface AlbumListPaginatedTableProps extends ItemListTableComponentProps<AlbumListQuery> {}
|
interface AlbumListPaginatedTableProps extends ItemListTableComponentProps<AlbumListQuery> {}
|
||||||
|
|
||||||
@@ -63,6 +65,10 @@ export const AlbumListPaginatedTable = forwardRef<any, AlbumListPaginatedTablePr
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.ALBUM,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListWithPagination
|
<ItemListWithPagination
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
@@ -87,6 +93,7 @@ export const AlbumListPaginatedTable = forwardRef<any, AlbumListPaginatedTablePr
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.ALBUM}
|
itemType={LibraryItem.ALBUM}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
size={size}
|
size={size}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
||||||
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||||
@@ -61,6 +62,10 @@ export const AlbumArtistListInfiniteTable = forwardRef<any, AlbumArtistListInfin
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.ALBUM_ARTIST,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemTableList
|
<ItemTableList
|
||||||
autoFitColumns={autoFitColumns}
|
autoFitColumns={autoFitColumns}
|
||||||
@@ -78,6 +83,7 @@ export const AlbumArtistListInfiniteTable = forwardRef<any, AlbumArtistListInfin
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.ALBUM_ARTIST}
|
itemType={LibraryItem.ALBUM_ARTIST}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onRangeChanged={onRangeChanged}
|
onRangeChanged={onRangeChanged}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
||||||
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
||||||
@@ -16,6 +17,7 @@ import {
|
|||||||
LibraryItem,
|
LibraryItem,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
} from '/@/shared/types/domain-types';
|
} from '/@/shared/types/domain-types';
|
||||||
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface AlbumArtistListPaginatedTableProps
|
interface AlbumArtistListPaginatedTableProps
|
||||||
extends ItemListTableComponentProps<AlbumArtistListQuery> {}
|
extends ItemListTableComponentProps<AlbumArtistListQuery> {}
|
||||||
@@ -64,6 +66,10 @@ export const AlbumArtistListPaginatedTable = forwardRef<any, AlbumArtistListPagi
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.ALBUM_ARTIST,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListWithPagination
|
<ItemListWithPagination
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
@@ -89,6 +95,7 @@ export const AlbumArtistListPaginatedTable = forwardRef<any, AlbumArtistListPagi
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.ALBUM_ARTIST}
|
itemType={LibraryItem.ALBUM_ARTIST}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
size={size}
|
size={size}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
||||||
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||||
@@ -60,6 +61,10 @@ export const ArtistListInfiniteTable = forwardRef<any, ArtistListInfiniteTablePr
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.ARTIST,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemTableList
|
<ItemTableList
|
||||||
autoFitColumns={autoFitColumns}
|
autoFitColumns={autoFitColumns}
|
||||||
@@ -77,6 +82,7 @@ export const ArtistListInfiniteTable = forwardRef<any, ArtistListInfiniteTablePr
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.ARTIST}
|
itemType={LibraryItem.ARTIST}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onRangeChanged={onRangeChanged}
|
onRangeChanged={onRangeChanged}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
||||||
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||||
@@ -16,6 +17,7 @@ import {
|
|||||||
LibraryItem,
|
LibraryItem,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
} from '/@/shared/types/domain-types';
|
} from '/@/shared/types/domain-types';
|
||||||
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface ArtistListPaginatedTableProps extends ItemListTableComponentProps<ArtistListQuery> {}
|
interface ArtistListPaginatedTableProps extends ItemListTableComponentProps<ArtistListQuery> {}
|
||||||
|
|
||||||
@@ -63,6 +65,10 @@ export const ArtistListPaginatedTable = forwardRef<any, ArtistListPaginatedTable
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.ARTIST,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListWithPagination
|
<ItemListWithPagination
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
@@ -88,6 +94,7 @@ export const ArtistListPaginatedTable = forwardRef<any, ArtistListPaginatedTable
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.ARTIST}
|
itemType={LibraryItem.ARTIST}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
size={size}
|
size={size}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
||||||
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||||
@@ -60,6 +61,10 @@ export const GenreListInfiniteTable = forwardRef<any, GenreListInfiniteTableProp
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.GENRE,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemTableList
|
<ItemTableList
|
||||||
autoFitColumns={autoFitColumns}
|
autoFitColumns={autoFitColumns}
|
||||||
@@ -77,6 +82,7 @@ export const GenreListInfiniteTable = forwardRef<any, GenreListInfiniteTableProp
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.GENRE}
|
itemType={LibraryItem.GENRE}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onRangeChanged={onRangeChanged}
|
onRangeChanged={onRangeChanged}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
||||||
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
||||||
@@ -16,6 +17,7 @@ import {
|
|||||||
LibraryItem,
|
LibraryItem,
|
||||||
SortOrder,
|
SortOrder,
|
||||||
} from '/@/shared/types/domain-types';
|
} from '/@/shared/types/domain-types';
|
||||||
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface GenreListPaginatedTableProps extends ItemListTableComponentProps<GenreListQuery> {}
|
interface GenreListPaginatedTableProps extends ItemListTableComponentProps<GenreListQuery> {}
|
||||||
|
|
||||||
@@ -63,6 +65,10 @@ export const GenreListPaginatedTable = forwardRef<any, GenreListPaginatedTablePr
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.GENRE,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListWithPagination
|
<ItemListWithPagination
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
@@ -88,6 +94,7 @@ export const GenreListPaginatedTable = forwardRef<any, GenreListPaginatedTablePr
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.GENRE}
|
itemType={LibraryItem.GENRE}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
size={size}
|
size={size}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
import { useItemListInfiniteLoader } from '/@/renderer/components/item-list/helpers/item-list-infinite-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
||||||
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||||
@@ -55,6 +56,10 @@ export const SongListInfiniteTable = forwardRef<any, SongListInfiniteTableProps>
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.SONG,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemTableList
|
<ItemTableList
|
||||||
autoFitColumns={autoFitColumns}
|
autoFitColumns={autoFitColumns}
|
||||||
@@ -71,6 +76,7 @@ export const SongListInfiniteTable = forwardRef<any, SongListInfiniteTableProps>
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.SONG}
|
itemType={LibraryItem.SONG}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onRangeChanged={onRangeChanged}
|
onRangeChanged={onRangeChanged}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
||||||
|
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
|
||||||
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
import { useItemListScrollPersist } from '/@/renderer/components/item-list/helpers/use-item-list-scroll-persist';
|
||||||
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
import { ItemListWithPagination } from '/@/renderer/components/item-list/item-list-pagination/item-list-pagination';
|
||||||
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
import { useItemListPagination } from '/@/renderer/components/item-list/item-list-pagination/use-item-list-pagination';
|
||||||
@@ -11,6 +12,7 @@ import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table
|
|||||||
import { ItemListTableComponentProps } from '/@/renderer/components/item-list/types';
|
import { ItemListTableComponentProps } from '/@/renderer/components/item-list/types';
|
||||||
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
||||||
import { LibraryItem, SongListQuery, SongListSort, SortOrder } from '/@/shared/types/domain-types';
|
import { LibraryItem, SongListQuery, SongListSort, SortOrder } from '/@/shared/types/domain-types';
|
||||||
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface SongListPaginatedTableProps extends ItemListTableComponentProps<SongListQuery> {}
|
interface SongListPaginatedTableProps extends ItemListTableComponentProps<SongListQuery> {}
|
||||||
|
|
||||||
@@ -58,6 +60,10 @@ export const SongListPaginatedTable = forwardRef<any, SongListPaginatedTableProp
|
|||||||
enabled: saveScrollOffset,
|
enabled: saveScrollOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { handleColumnResized } = useItemListColumnResize({
|
||||||
|
itemListKey: ItemListKey.SONG,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListWithPagination
|
<ItemListWithPagination
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
@@ -82,6 +88,7 @@ export const SongListPaginatedTable = forwardRef<any, SongListPaginatedTableProp
|
|||||||
type: 'offset',
|
type: 'offset',
|
||||||
}}
|
}}
|
||||||
itemType={LibraryItem.SONG}
|
itemType={LibraryItem.SONG}
|
||||||
|
onColumnResized={handleColumnResized}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
size={size}
|
size={size}
|
||||||
|
|||||||
Reference in New Issue
Block a user