From 6ae103850ba826a7ed30f6874aadabfead73b77d Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 3 Oct 2025 17:52:57 -0700 Subject: [PATCH] progress on table columns --- .../columns/default-column.tsx | 25 +++++++ .../columns/duration-column.tsx | 23 +++++++ .../item-table-list/columns/genre-column.tsx | 21 ++++++ .../columns/image-column.module.css | 3 + .../item-table-list/columns/image-column.tsx | 28 ++++++++ .../item-table-list/columns/name-column.tsx | 21 ++++++ .../columns/row-index-column.tsx | 8 +++ .../item-table-list-column.module.css | 21 ++++++ .../item-table-list-column.tsx | 65 +++++++++++++++++++ src/shared/types/types.ts | 6 +- 10 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 src/renderer/components/item-list/item-table-list/columns/default-column.tsx create mode 100644 src/renderer/components/item-list/item-table-list/columns/duration-column.tsx create mode 100644 src/renderer/components/item-list/item-table-list/columns/genre-column.tsx create mode 100644 src/renderer/components/item-list/item-table-list/columns/image-column.module.css create mode 100644 src/renderer/components/item-list/item-table-list/columns/image-column.tsx create mode 100644 src/renderer/components/item-list/item-table-list/columns/name-column.tsx create mode 100644 src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx create mode 100644 src/renderer/components/item-list/item-table-list/item-table-list-column.module.css create mode 100644 src/renderer/components/item-list/item-table-list/item-table-list-column.tsx diff --git a/src/renderer/components/item-list/item-table-list/columns/default-column.tsx b/src/renderer/components/item-list/item-table-list/columns/default-column.tsx new file mode 100644 index 000000000..7c3d31d53 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/default-column.tsx @@ -0,0 +1,25 @@ +import { + ItemTableListInnerColumn, + TableColumnContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { Skeleton } from '/@/shared/components/skeleton/skeleton'; + +export const DefaultColumn = (props: ItemTableListInnerColumn) => { + const row: any | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[ + props.columns[props.columnIndex].id + ]; + + if (typeof row === 'string') { + return {row}; + } + + if (typeof row === 'undefined') { + return ( + + + + ); + } + + return null; +}; diff --git a/src/renderer/components/item-list/item-table-list/columns/duration-column.tsx b/src/renderer/components/item-list/item-table-list/columns/duration-column.tsx new file mode 100644 index 000000000..a663834c5 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/duration-column.tsx @@ -0,0 +1,23 @@ +import formatDuration from 'format-duration'; + +import { + ItemTableListInnerColumn, + TableColumnContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { Skeleton } from '/@/shared/components/skeleton/skeleton'; + +export const DurationColumn = (props: ItemTableListInnerColumn) => { + const row: number | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[ + props.columns[props.columnIndex].id + ]; + + if (typeof row === 'number') { + return {formatDuration(row)}; + } + + return ( + + + + ); +}; diff --git a/src/renderer/components/item-list/item-table-list/columns/genre-column.tsx b/src/renderer/components/item-list/item-table-list/columns/genre-column.tsx new file mode 100644 index 000000000..86ebea4c2 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/genre-column.tsx @@ -0,0 +1,21 @@ +import { + ItemTableListInnerColumn, + TableColumnContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { Genre } from '/@/shared/types/domain-types'; + +export const GenreColumn = (props: ItemTableListInnerColumn) => { + const row: Genre[] | undefined = (props.data as (Genre[] | undefined)[])[props.rowIndex]?.[ + props.columns[props.columnIndex].id + ]; + + if (Array.isArray(row)) { + return ( + + {row.map((genre) => genre?.name).join(', ')} + + ); + } + + return null; +}; diff --git a/src/renderer/components/item-list/item-table-list/columns/image-column.module.css b/src/renderer/components/item-list/item-table-list/columns/image-column.module.css new file mode 100644 index 000000000..dc4f6d26e --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/image-column.module.css @@ -0,0 +1,3 @@ +.skeleton { + aspect-ratio: 1 / 1; +} diff --git a/src/renderer/components/item-list/item-table-list/columns/image-column.tsx b/src/renderer/components/item-list/item-table-list/columns/image-column.tsx new file mode 100644 index 000000000..8cec634ba --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/image-column.tsx @@ -0,0 +1,28 @@ +import styles from './image-column.module.css'; + +import { + ItemTableListInnerColumn, + TableColumnContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { Image } from '/@/shared/components/image/image'; +import { Skeleton } from '/@/shared/components/skeleton/skeleton'; + +export const ImageColumn = (props: ItemTableListInnerColumn) => { + const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[ + props.columns[props.columnIndex].id + ]; + + if (typeof row === 'string') { + return ( + + + + ); + } + + return ( + + + + ); +}; diff --git a/src/renderer/components/item-list/item-table-list/columns/name-column.tsx b/src/renderer/components/item-list/item-table-list/columns/name-column.tsx new file mode 100644 index 000000000..99fef4e3c --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/name-column.tsx @@ -0,0 +1,21 @@ +import { + ItemTableListInnerColumn, + TableColumnContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; +import { Skeleton } from '/@/shared/components/skeleton/skeleton'; + +export const NameColumn = (props: ItemTableListInnerColumn) => { + const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[ + props.columns[props.columnIndex].id + ]; + + if (typeof row === 'string') { + return {row}; + } + + return ( + + + + ); +}; diff --git a/src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx b/src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx new file mode 100644 index 000000000..4eda35446 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/columns/row-index-column.tsx @@ -0,0 +1,8 @@ +import { + ItemTableListInnerColumn, + TableColumnContainer, +} from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; + +export const RowIndexColumn = (props: ItemTableListInnerColumn) => { + return {props.rowIndex + 1}; +}; diff --git a/src/renderer/components/item-list/item-table-list/item-table-list-column.module.css b/src/renderer/components/item-list/item-table-list/item-table-list-column.module.css new file mode 100644 index 000000000..dbe352067 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/item-table-list-column.module.css @@ -0,0 +1,21 @@ +.container { + display: flex; + flex-direction: column; + justify-content: center; + height: 100%; + padding: var(--theme-spacing-xs); +} + +.content { + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + line-clamp: 2; + -webkit-box-orient: vertical; + line-height: 1.3; +} + +.container.compact { + padding: var(--theme-spacing-xs); +} diff --git a/src/renderer/components/item-list/item-table-list/item-table-list-column.tsx b/src/renderer/components/item-list/item-table-list/item-table-list-column.tsx new file mode 100644 index 000000000..8e66281f1 --- /dev/null +++ b/src/renderer/components/item-list/item-table-list/item-table-list-column.tsx @@ -0,0 +1,65 @@ +import clsx from 'clsx'; +import { CellComponentProps } from 'react-window-v2'; + +import styles from './item-table-list-column.module.css'; + +import { DefaultColumn } from '/@/renderer/components/item-list/item-table-list/columns/default-column'; +import { DurationColumn } from '/@/renderer/components/item-list/item-table-list/columns/duration-column'; +import { GenreColumn } from '/@/renderer/components/item-list/item-table-list/columns/genre-column'; +import { ImageColumn } from '/@/renderer/components/item-list/item-table-list/columns/image-column'; +import { RowIndexColumn } from '/@/renderer/components/item-list/item-table-list/columns/row-index-column'; +import { CellProps } from '/@/renderer/components/item-list/item-table-list/item-table-list'; +import { Text } from '/@/shared/components/text/text'; +import { TableColumn } from '/@/shared/types/types'; + +export interface ItemTableListColumn extends CellComponentProps {} + +export interface ItemTableListInnerColumn extends ItemTableListColumn { + type: TableColumn; +} + +export const ItemTableListColumn = (props: ItemTableListColumn) => { + const type = props.columns[props.columnIndex].id as TableColumn; + + switch (type) { + case TableColumn.DURATION: + return ; + case TableColumn.GENRE: + return ; + case TableColumn.IMAGE: + return ; + case TableColumn.ROW_INDEX: + return ; + default: + return ; + } +}; + +const NonMutedColumns = [TableColumn.TITLE]; + +export const TableColumnContainer = ( + props: ItemTableListColumn & { + children: React.ReactNode; + className?: string; + containerClassName?: string; + type: TableColumn; + }, +) => { + return ( +
props.handleExpand(e, props.data[props.rowIndex], props.itemType)} + style={props.style} + > + + {props.children} + +
+ ); +}; diff --git a/src/shared/types/types.ts b/src/shared/types/types.ts index 7c2a0eec0..eb918fdfd 100644 --- a/src/shared/types/types.ts +++ b/src/shared/types/types.ts @@ -156,7 +156,9 @@ export enum TableColumn { DATE_ADDED = 'dateAdded', DISC_NUMBER = 'discNumber', DURATION = 'duration', - GENRE = 'genre', + GENRE = 'genres', + ID = 'id', + IMAGE = 'imageUrl', LAST_PLAYED = 'lastPlayedAt', OWNER = 'username', PATH = 'path', @@ -166,7 +168,7 @@ export enum TableColumn { SIZE = 'size', SKIP = 'skip', SONG_COUNT = 'songCount', - TITLE = 'title', + TITLE = 'name', TITLE_COMBINED = 'titleCombined', TRACK_NUMBER = 'trackNumber', USER_FAVORITE = 'userFavorite',