mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 13:00:13 +02:00
add remaining table columns
This commit is contained in:
@@ -15,8 +15,9 @@ export const ActionsColumn = (props: ItemTableListInnerColumn) => {
|
||||
icon="ellipsisHorizontal"
|
||||
iconProps={{
|
||||
color: 'muted',
|
||||
size: 'lg',
|
||||
size: 'md',
|
||||
}}
|
||||
size="xs"
|
||||
variant="subtle"
|
||||
/>
|
||||
</TableColumnContainer>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
.group {
|
||||
gap: var(--theme-spacing-sm) var(--theme-spacing-xs);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.group a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.artists-container {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
line-height: 1.4;
|
||||
-webkit-box-orient: vertical;
|
||||
color: var(--theme-colors-foreground-muted);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { memo, useMemo } from 'react';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
|
||||
import styles from './album-artists-column.module.css';
|
||||
|
||||
import {
|
||||
ItemTableListInnerColumn,
|
||||
TableColumnContainer,
|
||||
TableColumnTextContainer,
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { RelatedAlbumArtist } from '/@/shared/types/domain-types';
|
||||
|
||||
const ArtistsColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: RelatedAlbumArtist[] | undefined = (
|
||||
props.data as (RelatedAlbumArtist[] | undefined)[]
|
||||
)[props.rowIndex]?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const artists = useMemo(() => {
|
||||
if (!row) return [];
|
||||
return row.map((artist) => {
|
||||
const path = generatePath(AppRoute.LIBRARY_ARTISTS_DETAIL, {
|
||||
artistId: artist.id,
|
||||
});
|
||||
return { ...artist, path };
|
||||
});
|
||||
}, [row]);
|
||||
|
||||
if (Array.isArray(row)) {
|
||||
return (
|
||||
<TableColumnContainer {...props}>
|
||||
<div className={styles.artistsContainer}>
|
||||
{artists.map((artist, index) => (
|
||||
<Text
|
||||
component={Link}
|
||||
isLink
|
||||
isMuted
|
||||
isNoSelect
|
||||
key={artist.id}
|
||||
to={artist.path}
|
||||
>
|
||||
{artist.name}
|
||||
{index < artists.length - 1 && ', '}
|
||||
</Text>
|
||||
))}
|
||||
</div>
|
||||
</TableColumnContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TableColumnTextContainer {...props}>
|
||||
<Skeleton />
|
||||
</TableColumnTextContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const ArtistsColumnMemo = memo(ArtistsColumn);
|
||||
|
||||
export { ArtistsColumnMemo as ArtistsColumn };
|
||||
@@ -18,8 +18,9 @@ export const FavoriteColumn = (props: ItemTableListInnerColumn) => {
|
||||
iconProps={{
|
||||
color: row ? 'primary' : 'muted',
|
||||
fill: row ? 'primary' : undefined,
|
||||
size: 'lg',
|
||||
size: 'md',
|
||||
}}
|
||||
size="xs"
|
||||
variant="subtle"
|
||||
/>
|
||||
</TableColumnContainer>
|
||||
|
||||
@@ -12,7 +12,11 @@ export const RatingColumn = (props: ItemTableListInnerColumn) => {
|
||||
if (typeof row === 'number' || row === null) {
|
||||
return (
|
||||
<TableColumnContainer {...props}>
|
||||
<Rating className={row ? undefined : 'hover-only-flex'} value={row || 0} />
|
||||
<Rating
|
||||
className={row ? undefined : 'hover-only-flex'}
|
||||
size="xs"
|
||||
value={row || 0}
|
||||
/>
|
||||
</TableColumnContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export const RowIndexColumn = (props: ItemTableListInnerColumn) => {
|
||||
<ActionIcon
|
||||
className={clsx(styles.expand, 'hover-only')}
|
||||
icon="arrowDownS"
|
||||
iconProps={{ color: 'muted', size: 'xl' }}
|
||||
iconProps={{ color: 'muted', size: 'md' }}
|
||||
onClick={(e) =>
|
||||
controls.onItemExpand?.(
|
||||
props.data[props.rowIndex] as any,
|
||||
@@ -27,6 +27,7 @@ export const RowIndexColumn = (props: ItemTableListInnerColumn) => {
|
||||
e,
|
||||
)
|
||||
}
|
||||
size="xs"
|
||||
variant="subtle"
|
||||
/>
|
||||
<Text className="hide-on-hover" isMuted>
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
.title-combined {
|
||||
display: grid;
|
||||
grid-template-columns: calc(var(--row-height) - var(--theme-spacing-sm)) 1fr;
|
||||
gap: var(--theme-spacing-sm);
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.text-container {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.artists {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 0.875rem;
|
||||
color: var(--theme-colors-foreground-muted);
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { CSSProperties, useMemo } from 'react';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
|
||||
import styles from './title-combined-column.module.css';
|
||||
|
||||
import {
|
||||
ItemTableListInnerColumn,
|
||||
TableColumnContainer,
|
||||
TableColumnTextContainer,
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { RelatedAlbumArtist } from '/@/shared/types/domain-types';
|
||||
|
||||
export const TitleCombinedColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: object | undefined = (props.data as (any | undefined)[])[props.rowIndex];
|
||||
|
||||
const artists = useMemo(() => {
|
||||
if (row && 'artists' in row && Array.isArray(row.artists)) {
|
||||
return (row.artists as RelatedAlbumArtist[]).map((artist) => {
|
||||
const path = generatePath(AppRoute.LIBRARY_ARTISTS_DETAIL, {
|
||||
artistId: artist.id,
|
||||
});
|
||||
return { ...artist, path };
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}, [row]);
|
||||
|
||||
if (row && 'name' in row && 'imageUrl' in row && 'artists' in row) {
|
||||
const rowHeight = props.getRowHeight(props.rowIndex, props);
|
||||
|
||||
return (
|
||||
<TableColumnContainer
|
||||
className={styles['title-combined']}
|
||||
containerStyle={{ '--row-height': `${rowHeight}px` } as CSSProperties}
|
||||
{...props}
|
||||
>
|
||||
<Image containerClassName={styles.image} src={row.imageUrl as string} />
|
||||
<div className={styles['text-container']}>
|
||||
<Text className={styles.title} isNoSelect>
|
||||
{row.name as string}
|
||||
</Text>
|
||||
<div className={styles.artists}>
|
||||
{artists.map((artist, index) => (
|
||||
<span key={artist.id}>
|
||||
<Text component={Link} isLink isMuted isNoSelect to={artist.path}>
|
||||
{artist.name}
|
||||
</Text>
|
||||
{index < artists.length - 1 && ', '}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</TableColumnContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TableColumnTextContainer {...props}>
|
||||
<Skeleton />
|
||||
</TableColumnTextContainer>
|
||||
);
|
||||
};
|
||||
@@ -32,6 +32,11 @@
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.content.compact {
|
||||
-webkit-line-clamp: 1;
|
||||
line-clamp: 1;
|
||||
}
|
||||
|
||||
.container.compact {
|
||||
padding: var(--theme-spacing-xs);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { ReactNode, useEffect, useRef } from 'react';
|
||||
import React, { CSSProperties, ReactNode, useEffect, useRef } from 'react';
|
||||
import { CellComponentProps } from 'react-window-v2';
|
||||
|
||||
import styles from './item-table-list-column.module.css';
|
||||
@@ -8,6 +8,7 @@ import i18n from '/@/i18n/i18n';
|
||||
import { itemListControls } from '/@/renderer/components/item-list/helpers/item-list-controls';
|
||||
import { ActionsColumn } from '/@/renderer/components/item-list/item-table-list/columns/actions-column';
|
||||
import { AlbumArtistsColumn } from '/@/renderer/components/item-list/item-table-list/columns/album-artists-column';
|
||||
import { ArtistsColumn } from '/@/renderer/components/item-list/item-table-list/columns/artists-column';
|
||||
import { CountColumn } from '/@/renderer/components/item-list/item-table-list/columns/count-column';
|
||||
import {
|
||||
DateColumn,
|
||||
@@ -24,6 +25,7 @@ import { RatingColumn } from '/@/renderer/components/item-list/item-table-list/c
|
||||
import { RowIndexColumn } from '/@/renderer/components/item-list/item-table-list/columns/row-index-column';
|
||||
import { SizeColumn } from '/@/renderer/components/item-list/item-table-list/columns/size-column';
|
||||
import { TextColumn } from '/@/renderer/components/item-list/item-table-list/columns/text-column';
|
||||
import { TitleCombinedColumn } from '/@/renderer/components/item-list/item-table-list/columns/title-combined-column';
|
||||
import { TableItemProps } from '/@/renderer/components/item-list/item-table-list/item-table-list';
|
||||
import { ItemControls } from '/@/renderer/components/item-list/types';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
@@ -82,6 +84,9 @@ export const ItemTableListColumn = (props: ItemTableListColumn) => {
|
||||
case TableColumn.SONG_COUNT:
|
||||
return <CountColumn {...props} controls={controls} type={type} />;
|
||||
|
||||
case TableColumn.ARTIST:
|
||||
return <ArtistsColumn {...props} controls={controls} type={type} />;
|
||||
|
||||
case TableColumn.BIOGRAPHY:
|
||||
case TableColumn.COMMENT:
|
||||
return <TextColumn {...props} controls={controls} type={type} />;
|
||||
@@ -119,6 +124,9 @@ export const ItemTableListColumn = (props: ItemTableListColumn) => {
|
||||
case TableColumn.SIZE:
|
||||
return <SizeColumn {...props} controls={controls} type={type} />;
|
||||
|
||||
case TableColumn.TITLE_COMBINED:
|
||||
return <TitleCombinedColumn {...props} controls={controls} type={type} />;
|
||||
|
||||
case TableColumn.USER_FAVORITE:
|
||||
return <FavoriteColumn {...props} controls={controls} type={type} />;
|
||||
|
||||
@@ -189,7 +197,9 @@ export const TableColumnTextContainer = (
|
||||
style={props.style}
|
||||
>
|
||||
<Text
|
||||
className={clsx(styles.content, props.className)}
|
||||
className={clsx(styles.content, props.className, {
|
||||
[styles.compact]: props.size === 'compact',
|
||||
})}
|
||||
isMuted={!NonMutedColumns.includes(props.type)}
|
||||
isNoSelect
|
||||
>
|
||||
@@ -203,7 +213,7 @@ export const TableColumnContainer = (
|
||||
props: ItemTableListColumn & {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
containerStyle?: CSSProperties;
|
||||
controls: ItemControls;
|
||||
type: TableColumn;
|
||||
},
|
||||
@@ -241,7 +251,7 @@ export const TableColumnContainer = (
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(styles.container, props.containerClassName, {
|
||||
className={clsx(styles.container, props.className, {
|
||||
[styles.center]: props.columns[props.columnIndex].align === 'center',
|
||||
[styles.compact]: props.size === 'compact',
|
||||
[styles.dataRow]: isDataRow,
|
||||
@@ -253,7 +263,7 @@ export const TableColumnContainer = (
|
||||
})}
|
||||
data-row-index={isDataRow ? props.rowIndex : undefined}
|
||||
ref={containerRef}
|
||||
style={props.style}
|
||||
style={{ ...props.containerStyle, ...props.style }}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
@@ -333,7 +343,7 @@ const columnLabelMap: Record<TableColumn, ReactNode | string> = {
|
||||
postProcess: 'upperCase',
|
||||
}) as string,
|
||||
[TableColumn.TITLE]: i18n.t('table.column.title', { postProcess: 'upperCase' }) as string,
|
||||
[TableColumn.TITLE_COMBINED]: i18n.t('table.column.titleCombined', {
|
||||
[TableColumn.TITLE_COMBINED]: i18n.t('table.column.title', {
|
||||
postProcess: 'upperCase',
|
||||
}) as string,
|
||||
[TableColumn.TRACK_NUMBER]: i18n.t('table.column.trackNumber', {
|
||||
|
||||
Reference in New Issue
Block a user