Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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));
}
Original file line number Diff line number Diff line change
@@ -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<string, unknown>

type EditAwareTracksTableProps = ComponentProps<typeof TracksTable> & {
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 (
<TracksTable
{...rest}
onClickRow={handleClickRow}
rowClassNameAddition={rowClassNameAddition}
/>
)
}
23 changes: 19 additions & 4 deletions packages/web/src/components/tracks-table/TracksTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<TableProps, 'onClickRow' | 'columns'>

const defaultColumns: TracksTableColumn[] = [
Expand Down Expand Up @@ -214,6 +220,7 @@ export const TracksTable = ({
data,
activeIndex,
trackActionsHeader,
rowClassNameAddition,
...tableProps
}: TracksTableProps) => {
const { isVirtualized, onClickRow } = tableProps
Expand Down Expand Up @@ -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[
Expand All @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ 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'
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'
Expand Down Expand Up @@ -349,7 +349,8 @@ const CollectionPage = ({ type }: CollectionPageProps) => {
<NoSearchResultsContent />
) : (
<div className={styles.tableWrapper}>
<TracksTable
<EditAwareTracksTable
collectionId={playlistId!}
// @ts-ignore
columns={tracksTableColumns}
wrapperClassName={styles.tracksTableWrapper}
Expand Down
Loading