Skip to content

Commit

Permalink
Create GridTrackTable - to replace TrackTables in the future
Browse files Browse the repository at this point in the history
  • Loading branch information
nukeop committed Aug 23, 2024
1 parent 74db02e commit 8088875
Show file tree
Hide file tree
Showing 8 changed files with 391 additions and 1 deletion.
10 changes: 9 additions & 1 deletion packages/app/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ module.exports = (env) => {
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread'
],
ignore: [/node_modules\/(?!@nuclear).*/]
include: [APP_DIR, ...NUCLEAR_MODULES]
}
};
const contentSecurity =
Expand Down Expand Up @@ -246,9 +246,17 @@ module.exports = (env) => {
static: {
publicPath: '/'
},
watchFiles: ['../../packages/**/*.{js,jsx,ts,tsx}'],
allowedHosts: 'all'
};

config.watchOptions = {
ignored: ['node_modules', 'dist'],
aggregateTimeout: 300,
poll: 1000
};
}


return config;
};
19 changes: 19 additions & 0 deletions packages/ui/lib/components/GridTrackTable/Cells/TextCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

import React from 'react';
import { CellProps } from 'react-table';
import cx from 'classnames';

import { Track } from '@nuclear/core';

import styles from '../styles.scss';


export const TextCell: React.FC<CellProps<Track>> = ({
cell,
value
}) => <div
{...cell.getCellProps()}
className={cx(styles.track_table_cell)}
>
{value}
</div>;
16 changes: 16 additions & 0 deletions packages/ui/lib/components/GridTrackTable/Cells/ThumbnailCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { CellProps } from 'react-table';
import cx from 'classnames';

import { Track } from '../../../types';
import styles from '../styles.scss';

export const ThumbnailCell: React.FC<CellProps<Track>> = ({
cell,
value
}) => <div
className={cx(styles.track_table_cell, styles.thumbnail_cell)}
{...cell.getCellProps()}
>
<img className={styles.thumbnail_cell_thumbnail} src={value} />
</div>;
30 changes: 30 additions & 0 deletions packages/ui/lib/components/GridTrackTable/Headers/TextHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ColumnInstance, UseSortByColumnProps } from 'react-table';
import { Track } from '../../../types';
import React from 'react';
import { Icon } from 'semantic-ui-react';

type TextHeaderProps = {
column: ColumnInstance<Track> & UseSortByColumnProps<Track>;
header: string | React.ReactNode;
'data-testid'?: string;
};

export const TextHeader: React.FC<TextHeaderProps> = ({
column,
header,
'data-testid': dataTestId
}) => {
const { isSorted, isSortedDesc } = column;
const name = isSortedDesc
? 'sort content descending' : 'sort content ascending';

return (
<div data-testid={dataTestId}>
{header}
{
isSorted &&
<Icon name={name} />
}
</div>
);
};
168 changes: 168 additions & 0 deletions packages/ui/lib/components/GridTrackTable/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { Row, TableInstance, TableState, UseSortByInstanceProps, UseSortByState, useSortBy, useTable } from 'react-table';
import React, { useMemo, memo } from 'react';
import { DragDropContext, DragDropContextProps, Draggable, Droppable } from 'react-beautiful-dnd';
import cx from 'classnames';
import { FixedSizeList, FixedSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';

import { TrackTableColumn, TrackTableHeaders, TrackTableSettings } from '../TrackTable/types';
import { TextHeader } from './Headers/TextHeader';
import { TextCell } from './Cells/TextCell';
import { Track } from '../../types';
import { getTrackThumbnail } from '../TrackRow';

import styles from './styles.scss';
import artPlaceholder from '../../../resources/media/art_placeholder.png';
import { ThumbnailCell } from './Cells/ThumbnailCell';

type GridTrackTableRowProps<T extends Track> = {
data: {
rows: TableInstance<T>['rows'];
prepareRow: TableInstance<T>['prepareRow'];
extraProps: TrackTableSettings;
};
index: number;
style: React.CSSProperties;
}

const GridTrackTableRow = memo(<T extends Track>({ index, style, data }: GridTrackTableRowProps<T>) => {
const row = data.rows[index];
data.prepareRow(row);
return <Draggable
key={row.id}
draggableId={row.id}
index={row.index}
isDragDisabled={false}
>
{
(draggableProvided, draggableSnapshot) => (
<div
data-test-id='track-table-row'
className={cx(
styles.track_table_row,
{ [styles.is_dragging]: draggableSnapshot.isDragging }
)}
ref={draggableProvided.innerRef}
{...row.getRowProps()}
{...draggableProvided.draggableProps}
{...draggableProvided.dragHandleProps}
style={style ? {
...draggableProvided.draggableProps.style,
...style
} : draggableProvided.draggableProps.style}
>
{row.cells.map((cell, i) => cell.render(
'Cell',
{ ...data.extraProps, key: i }
))}
</div>
)}
</Draggable>;
});

export type GridTrackTableProps<T extends Track> = {
tracks: T[];
onDragEnd?: DragDropContextProps['onDragEnd'];
} & TrackTableHeaders & TrackTableSettings;

export const GridTrackTable = <T extends Track>({
tracks,

titleHeader,
thumbnailHeader,

displayArtist=true,
displayThumbnail=true,

...extraProps
}: GridTrackTableProps<T>) => {
const columns = useMemo(() => [
displayThumbnail && {
id: TrackTableColumn.Thumbnail,
Header: () => <span className={styles.center_aligned}>{thumbnailHeader}</span>,
accessor: (track) => getTrackThumbnail(track) || artPlaceholder,
Cell: ThumbnailCell
},
{
id: TrackTableColumn.Title,
Header: ({ column }) => <TextHeader column={column} header={titleHeader} />,
accessor: (track) => track.title ?? track.name,
Cell: TextCell,
enableSorting: true
}
], [displayArtist, displayThumbnail]);

const data = useMemo(() => tracks, [tracks]);

const initialState: Partial<TableState<T> & UseSortByState<T>> = {
sortBy: [{ id: TrackTableColumn.Title, desc: false }]
};
const table = useTable<T>({ columns, data, initialState }, useSortBy) as (TableInstance<T> & UseSortByInstanceProps<T>);

const {getTableProps, getTableBodyProps, headerGroups, rows, prepareRow} = table;

return <div className={styles.track_table_wrapper}>
<div
className={styles.track_table}
{...getTableProps()}
>
<div className={styles.track_table_head}>
{headerGroups.map(headerGroup => (
<div
key={headerGroup.id}
className={styles.track_table_header_row}
{...headerGroup.getHeaderGroupProps()}
>
{
headerGroup.headers.map(column => (
<div
key={column.id}
className={styles.track_table_header_cell}
{...column.getHeaderProps()}
>
{column.render('Header')}
</div>))
}
</div>
))}
</div>
<DragDropContext onDragEnd={() => {}}>
<Droppable droppableId='track_table'>
{(droppableProvided) => (
<div
data-testid='track-table-body'
className={styles.track_table_body}
ref={droppableProvided.innerRef}
{...getTableBodyProps()}
{...droppableProvided.droppableProps}
>
<AutoSizer>
{({ height, width }) =>
<>
<FixedSizeList
height={829}
width={width}
itemSize={42}
itemCount={rows.length}
overscanCount={2}
itemData={{
rows: rows as Row<Track>[],
prepareRow: prepareRow as (row: Row<Track>) => void,
extraProps
}}
outerRef={droppableProvided.innerRef}
>
{GridTrackTableRow}
</FixedSizeList>
{droppableProvided.placeholder}
</>
}
</AutoSizer>
</div>
)}
</Droppable>
</DragDropContext>
</div>
</div>;
};

75 changes: 75 additions & 0 deletions packages/ui/lib/components/GridTrackTable/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
@import "../../common.scss";

.track_table_wrapper {
position: relative;
display: flex;
flex-flow: column;
overflow: hidden;
height: 100%;
}

.track_table {
position: relative;
display: flex;
flex-flow: column;
width: 100%;
flex: 1 1 auto;

.track_table_head {
display: grid;
background: $bgdefault;
color: $white;
grid-template-columns: 1fr;
flex: 0 0 auto;
}

.track_table_header_row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
width: 100%;
}

.track_table_header_cell {
display: table-cell;
padding: 1em;
text-align: left;
}

.track_table_body {
display: block;
gap: 0.25em;
overflow: auto;
flex: 1 1 auto;

&.body_dragged_over {
background: $bgdark;
}
}

.track_table_row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
gap: 1em;

color: $white;

&:hover {
background: rgba($bgdefault, 0.25);
}
}

.track_table_cell {
display: flex;
align-items: center;
}
}

.thumbnail_cell {
height: 3em;
.thumbnail_cell_thumbnail {
display: block;
width: 3em;
height: 3em;
object-fit: contain;
}
}
1 change: 1 addition & 0 deletions packages/ui/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export { default as FullscreenLayer } from './components/FullscreenLayer';
export { default as FullscreenForm } from './components/FullscreenForm';
export { default as FormInput } from './components/FormInput';
export { default as InputDialog } from './components/InputDialog';
export { GridTrackTable } from './components/GridTrackTable';

export {NuclearSignInForm} from './forms/NuclearSignInForm';
export {NuclearSignUpForm} from './forms/NuclearSignUpForm';
Expand Down
Loading

0 comments on commit 8088875

Please sign in to comment.