From 63012f40355a1c59354e762d285afd6513a853cc Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 17 Sep 2021 00:55:26 -0700 Subject: [PATCH] add initial context menu fix default click - remove preventDefault() from root container --- src/__tests__/App.test.tsx | 4 +++ src/components/layout/Layout.tsx | 36 +++++++++++++++---- src/components/layout/Sidebar.tsx | 2 ++ src/components/layout/styled.tsx | 1 + src/components/shared/ContextMenu.tsx | 33 +++++++++++++++++ src/components/shared/styled.ts | 42 ++++++++++++++++++++++ src/components/viewtypes/ListViewTable.tsx | 36 ++++++++++++++++--- src/components/viewtypes/ListViewType.tsx | 40 ++++++++++++++++++++- src/redux/miscSlice.ts | 28 +++++++++++++++ src/styles/custom-theme.less | 4 +++ 10 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 src/components/shared/ContextMenu.tsx diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index 3ec7542..f7f296a 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -66,6 +66,10 @@ const playerState: Player = { const miscState: General = { theme: 'defaultDark', font: 'Poppins', + contextMenu: { + show: false, + }, + expandSidebar: false, modal: { currentPageIndex: undefined, show: false, diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx index 03092ab..1decccb 100644 --- a/src/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -1,16 +1,19 @@ -import React, { useState } from 'react'; +import React from 'react'; import { useHistory } from 'react-router-dom'; import { Content } from 'rsuite'; import Sidebar from './Sidebar'; import Titlebar from './Titlebar'; import { RootContainer, RootFooter, MainContainer } from './styled'; +import { setContextMenu, setExpandSidebar } from '../../redux/miscSlice'; +import { useAppDispatch, useAppSelector } from '../../redux/hooks'; const Layout = ({ footer, children, disableSidebar, font }: any) => { - const [expandSidebar, setExpandSidebar] = useState(false); const history = useHistory(); + const dispatch = useAppDispatch(); + const misc = useAppSelector((state) => state.misc); const handleToggle = () => { - setExpandSidebar(!expandSidebar); + dispatch(setExpandSidebar(!misc.expandSidebar)); }; const handleSidebarSelect = (e: string) => { @@ -56,14 +59,35 @@ const Layout = ({ footer, children, disableSidebar, font }: any) => { <> { + if (misc.contextMenu.show === true) { + dispatch( + setContextMenu({ + show: false, + }) + ); + } + }} /> - - + { + if (misc.contextMenu.show === true) { + dispatch( + setContextMenu({ + show: false, + }) + ); + } + }} + > + {children} {footer} diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 4bb8e73..9d88a8d 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -8,6 +8,7 @@ const Sidebar = ({ handleSidebarSelect, disableSidebar, font, + ...rest }: any) => { return ( ` diff --git a/src/components/shared/ContextMenu.tsx b/src/components/shared/ContextMenu.tsx new file mode 100644 index 0000000..04f42e2 --- /dev/null +++ b/src/components/shared/ContextMenu.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { ContextMenuWindow, StyledContextMenuButton } from './styled'; + +export const ContextMenuButton = ({ children, ...rest }: any) => { + return ( + + {children} + + ); +}; + +export const NowPlayingContextMenu = ({ + yPos, + xPos, + width, + numOfButtons, + numOfDividers, + hasTitle, + children, +}: any) => { + return ( + + {children} + + ); +}; diff --git a/src/components/shared/styled.ts b/src/components/shared/styled.ts index 9567c97..8897fe6 100644 --- a/src/components/shared/styled.ts +++ b/src/components/shared/styled.ts @@ -156,3 +156,45 @@ export const StyledInputPicker = styled(InputPicker)<{ width?: number }>` export const StyledIcon = styled(Icon)` color: ${(props) => `${props.theme.primary.main} !important`}; `; + +export const ContextMenuWindow = styled.div<{ + yPos: number; + xPos: number; + numOfButtons: number; + numOfDividers: number; + width: number; + hasTitle: boolean; +}>` + position: absolute; + top: ${(props) => `${props.yPos}px`}; + left: ${(props) => `${props.xPos}px`}; + height: ${(props) => + `${ + props.numOfButtons * 30 + + props.numOfDividers * 7 + + (props.hasTitle ? 16 : 0) + }px`}; + width: ${(props) => `${props.width}px`}; + margin: 0px; + white-space: normal; + overflow: hidden; + overflow-x: hidden; + font-size: smaller; + background: ${(props) => props.theme.primary.background}; + border: 1px #3c4043 solid; +`; + +export const StyledContextMenuButton = styled(Button)` + text-align: left; +`; + +export const ContextMenuDivider = styled.hr` + margin: 5px 0 5px 0; +`; + +export const ContextMenuTitle = styled.div` + color: ${(props) => props.theme.primary.text}; + margin-left: 5px; + margin-top: 5px; + user-select: none; +`; diff --git a/src/components/viewtypes/ListViewTable.tsx b/src/components/viewtypes/ListViewTable.tsx index 95b571c..bfc59f1 100644 --- a/src/components/viewtypes/ListViewTable.tsx +++ b/src/components/viewtypes/ListViewTable.tsx @@ -24,7 +24,7 @@ import { } from '../../shared/utils'; import cacheImage from '../shared/cacheImage'; import { setRating, star, unstar } from '../../api/api'; -import { useAppDispatch } from '../../redux/hooks'; +import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { fixPlayer2Index, setSort, @@ -32,7 +32,7 @@ import { sortPlayQueue, } from '../../redux/playQueueSlice'; import { StyledIconToggle, StyledRate } from '../shared/styled'; -import { addModalPage } from '../../redux/miscSlice'; +import { addModalPage, setContextMenu } from '../../redux/miscSlice'; import { setCurrentMouseOverId, setIsDragging, @@ -62,6 +62,7 @@ const ListViewTable = ({ }: any) => { const history = useHistory(); const dispatch = useAppDispatch(); + const misc = useAppSelector((state) => state.misc); const queryClient = useQueryClient(); const [cachePath] = useState(path.join(getImageCachePath(), '/')); const [sortColumn, setSortColumn] = useState(); @@ -203,6 +204,34 @@ const ListViewTable = ({ sortColumn={nowPlaying ? playQueue.sortColumn : sortColumn} sortType={nowPlaying ? playQueue.sortType : sortType} onSortColumn={handleSortColumn} + onRowContextMenu={(rowData: any, e: any) => { + e.preventDefault(); + if ( + (misc.contextMenu.show === false || + misc.contextMenu.rowId !== rowData.uniqueId) && + multiSelect.selected.filter( + (entry: any) => entry.uniqueId === rowData.uniqueId + ).length > 0 + ) { + const xFix = misc.expandSidebar ? 185 : 50; + const yFix = nowPlaying ? 150 : 215; + dispatch( + setContextMenu({ + show: true, + xPos: e.pageX - xFix, + yPos: e.pageY - yFix, + rowId: rowData.uniqueId, + type: nowPlaying ? 'nowPlaying' : 'other', + }) + ); + } else { + dispatch( + setContextMenu({ + show: false, + }) + ); + } + }} // onScroll={onScroll} > {columns.map((column: any) => ( @@ -233,7 +262,6 @@ const ListViewTable = ({ {(rowData: any, rowIndex: any) => { return ( console.log('fuck')} playing={ (rowData.uniqueId === playQueue?.currentSongUniqueId && nowPlaying) || @@ -698,7 +726,7 @@ const ListViewTable = ({ /> ) : column.dataKey === 'userRating' ? ( { + const misc = useAppSelector((state) => state.misc); const [isDragging, setIsDragging] = useState(false); const [dragDirection, setDragDirection] = useState(''); const [dragSpeed, setDragSpeed] = useState(''); @@ -346,6 +352,38 @@ const ListViewType = ( /> )} + {misc.contextMenu.show && misc.contextMenu.type === 'nowPlaying' && ( + + + Selected: {multiSelect.selected.length} + + + Remove from queue + + + Add to playlist + + Add favorite + Remove favorite + + + View details + + + + + )} ); }; diff --git a/src/redux/miscSlice.ts b/src/redux/miscSlice.ts index daeec47..7841309 100644 --- a/src/redux/miscSlice.ts +++ b/src/redux/miscSlice.ts @@ -12,12 +12,22 @@ export interface Modal { show: boolean; currentPageIndex: number | undefined; } + +export interface ContextMenu { + show: boolean; + xPos?: number; + yPos?: number; + rowId?: string; + type?: string; +} export interface General { theme: string; font: string; modal: Modal; modalPages: ModalPage[]; + expandSidebar: boolean; isProcessingPlaylist: string[]; + contextMenu: ContextMenu; } const initialState: General = { @@ -28,13 +38,29 @@ const initialState: General = { currentPageIndex: undefined, }, modalPages: [], + expandSidebar: false, isProcessingPlaylist: [], + contextMenu: { + show: false, + }, }; const miscSlice = createSlice({ name: 'misc', initialState, reducers: { + setExpandSidebar: (state, action: PayloadAction) => { + state.expandSidebar = action.payload; + }, + + setContextMenu: (state, action: PayloadAction) => { + state.contextMenu.show = action.payload.show; + state.contextMenu.xPos = action.payload.xPos; + state.contextMenu.yPos = action.payload.yPos; + state.contextMenu.rowId = action.payload.rowId; + state.contextMenu.type = action.payload.type; + }, + addProcessingPlaylist: (state, action: PayloadAction) => { state.isProcessingPlaylist.push(action.payload); }, @@ -111,5 +137,7 @@ export const { decrementModalPage, addProcessingPlaylist, removeProcessingPlaylist, + setContextMenu, + setExpandSidebar, } = miscSlice.actions; export default miscSlice.reducer; diff --git a/src/styles/custom-theme.less b/src/styles/custom-theme.less index 24cbbc2..ec597ee 100644 --- a/src/styles/custom-theme.less +++ b/src/styles/custom-theme.less @@ -1,6 +1,10 @@ // Main @body-bg: undefined; +// Rate +@rate-xs-font-size: 14px; +@rate-sm-font-size: 17px; + // Input @input-bg: undefined; @input-color: undefined;