Skip to content

Commit

Permalink
feat(playlist): add export set workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
nanochromatic committed Jan 28, 2024
1 parent 9660065 commit 2d5778d
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 22 deletions.
3 changes: 1 addition & 2 deletions src/components/MusicGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,10 @@ const getColDef: (
getQuickFilterText: (): string => '',
},
{
headerName: 'ID',
hide: !enableTrackIdCol,
cellRendererFramework: TrackIdRenderer,
resizable: false,
maxWidth: 20,
maxWidth: 35,
},
{
headerName: 'Title',
Expand Down
2 changes: 1 addition & 1 deletion src/components/renderers/LinkRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const LinkRenderer: React.FC<ILinkRenderer> = (params) => {
return hasLink ? (
<span>
<OverlayTrigger
delay={{ show: 250, hide: 100 }}
delay={{ show: 1000, hide: 100 }}
overlay={<Tooltip id={`tooltip-ext-link`}>View on YouTube</Tooltip>}
>
<a
Expand Down
54 changes: 49 additions & 5 deletions src/components/renderers/TrackIdRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
/** @jsxImportSource @emotion/react */
import React from 'react';
import React, { useMemo } from 'react';
import { ICellRendererParams } from 'ag-grid-community';
import { css } from '@emotion/react';
import { getKey } from '../utils/PlaylistUtils';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import { useAtom } from 'jotai';
import { trackExportSetAtom } from '../../state/playlist';

export const TrackIdRenderer: React.FC<ICellRendererParams> = (params) => {
const { data } = params;
const key = useMemo(() => getKey(data.source.structure, data.filename), [
data.source.structure,
data.filename,
]);
const [trackExportSet, setTrackExportSet] = useAtom(trackExportSetAtom);
const trackInExportSet = useMemo(() => trackExportSet.has(key), [
key,
trackExportSet,
]);

const onExportSetChange = () => {
if (trackInExportSet) {
trackExportSet.delete(key);
} else {
trackExportSet.add(key);
}
const newSet = new Set(trackExportSet);
setTrackExportSet(newSet);
};

return (
<span
Expand All @@ -16,14 +37,15 @@ export const TrackIdRenderer: React.FC<ICellRendererParams> = (params) => {
`}
>
<div
css={css`
margin: 0 5px;
`}
onClick={() => {
navigator.clipboard.writeText(
`"${getKey(data.source.structure, data.filename)}",\n`
);
navigator.clipboard.writeText(`"${key}",\n`);
}}
>
<OverlayTrigger
delay={{ show: 250, hide: 100 }}
delay={{ show: 1000, hide: 100 }}
overlay={
<Tooltip id={`tooltip-copy-track-id`}>Copy Track ID</Tooltip>
}
Expand All @@ -36,6 +58,28 @@ export const TrackIdRenderer: React.FC<ICellRendererParams> = (params) => {
/>
</OverlayTrigger>
</div>
<div onClick={onExportSetChange}>
<OverlayTrigger
delay={{ show: 1000, hide: 100 }}
overlay={
<Tooltip id={`tooltip-export`}>
{trackInExportSet
? 'Remove from Export Set'
: 'Add to Export Set'}
</Tooltip>
}
>
<i
css={css`
cursor: pointer;
color: ${trackInExportSet ? 'red' : 'green'};
`}
className={`fa-regular ${
trackInExportSet ? 'fa-square-minus' : 'fa-square-plus'
}`}
/>
</OverlayTrigger>
</div>
</span>
);
};
13 changes: 11 additions & 2 deletions src/pages/PlaylistBuilderPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,13 @@ const PlaylistBuilderPage: React.FC = () => {

return (
<div>
<div>
<div
css={css`
@media (min-width: 1024px) {
margin-right: 33vw;
}
`}
>
<h2>Playlist Builder</h2>
<p>
Import and export custom playlists. JSON structure can be found{' '}
Expand All @@ -107,7 +113,10 @@ const PlaylistBuilderPage: React.FC = () => {
>
here
</a>
; track IDs may be copied from the Playlist page.
; track IDs may be copied from the Playlist page. Tracks can also be
added to and removed from the Export Set on the Playlist page. The
Export Set can be copied and cleared from the Playlist Settings
dropdown.
</p>
<p
css={css`
Expand Down
77 changes: 65 additions & 12 deletions src/pages/PlaylistPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { emptyPlayingState, playingStateAtom } from '../state/player';
import SearchBar from '../components/SearchBar';
import { useDataSourceState } from '../context/DataSourceContext';
import Select from 'react-select';
import { playlistMapAtom, selectedPlaylistsAtom } from '../state/playlist';
import {
playlistMapAtom,
selectedPlaylistsAtom,
trackExportSetAtom,
} from '../state/playlist';
import { css } from '@emotion/react';
import { useTheme } from '../context/ThemeContext';
import { IPlayingState } from '../models/Player';
Expand All @@ -17,6 +21,8 @@ import {
getKey,
} from '../components/utils/PlaylistUtils';
import { sortBy } from 'lodash-es';
import { Dropdown } from 'react-bootstrap';
import { QueueActionButton } from '../components/QueueActionButton';

const PlaylistPage: React.FC = () => {
const appTheme = useTheme();
Expand Down Expand Up @@ -48,6 +54,7 @@ const PlaylistPage: React.FC = () => {
return [...dbPlaylists, ...customPlaylists];
}, [dbPlaylists, customPlaylists]);
const setSelectedPlaylists = useSetAtom(selectedPlaylistsAtom);
const [trackExportSet, setTrackExportSet] = useAtom(trackExportSetAtom);

useEffect(() => {
setPlayingState(emptyPlayingState);
Expand Down Expand Up @@ -98,6 +105,16 @@ const PlaylistPage: React.FC = () => {
setSelectedPlaylists(newValue.map((pl) => pl.value));
};

const onCopyExportSet = () => {
const strArr = Array.from(trackExportSet);
const str = JSON.stringify(strArr, null, 2);
navigator.clipboard.writeText(str);
};

const onClearExportSet = () => {
setTrackExportSet(new Set());
};

return (
<div>
{playingState.currentSong === undefined ? (
Expand All @@ -108,20 +125,56 @@ const PlaylistPage: React.FC = () => {
setCurrentQueueSong={setCurrentQueueSong}
/>
)}
<Select
<div
css={css`
display: flex;
margin: 10px 25vw;
justify-content: center;
align-items: center;
height: 46px;
`}
classNamePrefix={
appTheme.darkMode ? 'playlist-select-dark' : 'playlist-select'
}
isMulti
options={allPlaylists}
ref={selectRef}
value={selectedOption}
onChange={onSelectChange}
placeholder="Select playlist"
/>
>
<Select
css={css`
width: 100%;
`}
classNamePrefix={
appTheme.darkMode ? 'playlist-select-dark' : 'playlist-select'
}
isMulti
options={allPlaylists}
ref={selectRef}
value={selectedOption}
onChange={onSelectChange}
placeholder="Select playlist"
/>
<Dropdown
css={css`
height: 100%;
`}
>
<Dropdown.Toggle
css={css`
height: 100%;
`}
variant="outline-primary"
>
<i className="fa fa-cog"></i>
</Dropdown.Toggle>
<Dropdown.Menu>
<QueueActionButton
actionName="Copy Export Set"
iconClass="fa fa-copy"
onClick={onCopyExportSet}
/>
<QueueActionButton
actionName="Clear Export Set"
iconClass="fa fa-trash"
onClick={onClearExportSet}
/>
</Dropdown.Menu>
</Dropdown>
</div>
<SearchBar />
<MusicGrid dataSource={dataSource} disableInitSort enableTrackIdCol />
</div>
Expand Down
1 change: 1 addition & 0 deletions src/state/playlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export const selectedPlaylistAtom = atom((get) => {
? 'multi'
: selectedPlaylists[0];
});
export const trackExportSetAtom = atom<Set<string>>(new Set<string>());

0 comments on commit 2d5778d

Please sign in to comment.