diff --git a/packages/web/src/components/collection/desktop/edit-mode/tracks/EditAwareTracksTable.module.css b/packages/web/src/components/collection/desktop/edit-mode/tracks/EditAwareTracksTable.module.css new file mode 100644 index 00000000000..00fb5bab21e --- /dev/null +++ b/packages/web/src/components/collection/desktop/edit-mode/tracks/EditAwareTracksTable.module.css @@ -0,0 +1,5 @@ +.selected, +.selected td { + background-color: var(--harmony-bg-surface-2) !important; + box-shadow: inset 3px 0 0 0 var(--harmony-secondary, var(--harmony-accent)); +} diff --git a/packages/web/src/components/collection/desktop/edit-mode/tracks/EditAwareTracksTable.tsx b/packages/web/src/components/collection/desktop/edit-mode/tracks/EditAwareTracksTable.tsx new file mode 100644 index 00000000000..6ac5698df9b --- /dev/null +++ b/packages/web/src/components/collection/desktop/edit-mode/tracks/EditAwareTracksTable.tsx @@ -0,0 +1,83 @@ +import { ComponentProps, useCallback, useEffect, useRef } from 'react' + +import { ID } from '@audius/common/models' + +import { TracksTable } from 'components/tracks-table' + +import { usePlaylistEditMode } from '../PlaylistEditModeContext' + +import styles from './EditAwareTracksTable.module.css' +import { useTrackSelection } from './TrackSelectionContext' + +type TrackLike = { track_id?: number | null } & Record + +type EditAwareTracksTableProps = ComponentProps & { + collectionId: ID +} + +/** + * Wraps the standard TracksTable for the playlist detail page so that, while + * the page is in edit mode, clicking a row toggles selection (shift to extend + * the range) instead of activating playback. Outside of edit mode the + * behavior is identical to the underlying TracksTable. + */ +export const EditAwareTracksTable = (props: EditAwareTracksTableProps) => { + const { collectionId, onClickRow, ...rest } = props + const editMode = usePlaylistEditMode() + const selection = useTrackSelection() + const isEditingThis = + editMode.isEditMode && editMode.collectionId === collectionId + + // Capture shift modifier state from keyboard so we can extend the selection + // even though TracksTable's onClickRow does not pass the MouseEvent. + const shiftRef = useRef(false) + useEffect(() => { + if (!isEditingThis) { + shiftRef.current = false + return + } + const down = (e: KeyboardEvent) => { + if (e.key === 'Shift') shiftRef.current = true + } + const up = (e: KeyboardEvent) => { + if (e.key === 'Shift') shiftRef.current = false + } + window.addEventListener('keydown', down) + window.addEventListener('keyup', up) + return () => { + window.removeEventListener('keydown', down) + window.removeEventListener('keyup', up) + } + }, [isEditingThis]) + + const handleClickRow = useCallback( + (track: TrackLike, index: number) => { + if (!isEditingThis) { + onClickRow?.(track, index) + return + } + const id = track.track_id + if (typeof id !== 'number') return + selection.toggle(id, index, { shift: shiftRef.current }) + }, + [isEditingThis, onClickRow, selection] + ) + + const rowClassNameAddition = useCallback( + (track: TrackLike) => { + if (!isEditingThis) return undefined + const id = track.track_id + if (typeof id !== 'number') return undefined + return selection.isSelected(id) ? styles.selected : undefined + }, + [isEditingThis, selection] + ) + + return ( + + ) +} diff --git a/packages/web/src/components/tracks-table/TracksTable.tsx b/packages/web/src/components/tracks-table/TracksTable.tsx index d433a503943..dae2c233625 100644 --- a/packages/web/src/components/tracks-table/TracksTable.tsx +++ b/packages/web/src/components/tracks-table/TracksTable.tsx @@ -184,6 +184,12 @@ type TracksTableProps = { showArtistInTrackNameColumn?: boolean onClickRow?: (track: any, index: number) => void trackActionsHeader?: ReactNode + /** + * Optional additional className applied per row. The result is appended + * to the table's own per-row className. Use this for things like a + * selected-row highlight while the page is in edit mode. + */ + rowClassNameAddition?: (track: any, rowIndex: number) => string | undefined } & Omit const defaultColumns: TracksTableColumn[] = [ @@ -214,6 +220,7 @@ export const TracksTable = ({ data, activeIndex, trackActionsHeader, + rowClassNameAddition, ...tableProps }: TracksTableProps) => { const { isVirtualized, onClickRow } = tableProps @@ -1046,6 +1053,9 @@ export const TracksTable = ({ [activateTrack] ) + const rowClassNameAdditionRef = useRef(rowClassNameAddition) + rowClassNameAdditionRef.current = rowClassNameAddition + const getRowClassName = useCallback((rowIndex: number) => { const track = dataRef.current[rowIndex] const { isFetchingNFTAccess, hasStreamAccess } = trackAccessMapRef.current[ @@ -1058,10 +1068,15 @@ export const TracksTable = ({ const deleted = track.is_delete || track._marked_deleted || !!track.user?.is_deactivated const isPremium = isContentUSDCPurchaseGated(track.stream_conditions) - return cn(styles.tableRow, { - [styles.disabled]: deleted, - [styles.lockedRow]: isLocked && !deleted && !isPremium - }) + const extra = rowClassNameAdditionRef.current?.(track, rowIndex) + return cn( + styles.tableRow, + { + [styles.disabled]: deleted, + [styles.lockedRow]: isLocked && !deleted && !isPremium + }, + extra + ) }, []) return ( diff --git a/packages/web/src/pages/collection-page/components/desktop/CollectionPage.tsx b/packages/web/src/pages/collection-page/components/desktop/CollectionPage.tsx index f4a99a34b57..9405da2238d 100644 --- a/packages/web/src/pages/collection-page/components/desktop/CollectionPage.tsx +++ b/packages/web/src/pages/collection-page/components/desktop/CollectionPage.tsx @@ -24,6 +24,7 @@ import { CollectionDogEar } from 'components/collection' import { CollectionHeader } from 'components/collection/desktop/CollectionHeader' import { PlaylistEditModeBar } from 'components/collection/desktop/edit-mode/PlaylistEditModeBar' import { PlaylistEditModeProvider } from 'components/collection/desktop/edit-mode/PlaylistEditModeContext' +import { EditAwareTracksTable } from 'components/collection/desktop/edit-mode/tracks/EditAwareTracksTable' import { TrackBulkActionsBar } from 'components/collection/desktop/edit-mode/tracks/TrackBulkActionsBar' import { TrackHistoryProvider } from 'components/collection/desktop/edit-mode/tracks/TrackHistoryContext' import { TrackSelectionProvider } from 'components/collection/desktop/edit-mode/tracks/TrackSelectionContext' @@ -31,7 +32,6 @@ import FilterInput from 'components/filter-input/FilterInput' import Page from 'components/page/Page' import { SuggestedTracks } from 'components/suggested-tracks' import { RESPONSIVE_TABLE_POLICIES } from 'components/table/responsivePolicies' -import { TracksTable } from 'components/tracks-table' import { useRequiresAccountCallback } from 'hooks/useRequiresAccount' import { useMainContentRef } from 'pages/MainContentContext' import { computeCollectionMetadataProps } from 'pages/collection-page/store/utils' @@ -349,7 +349,8 @@ const CollectionPage = ({ type }: CollectionPageProps) => { ) : (
-