Browse Source

Add refs for picker components

master
jeffvli 3 years ago
committed by Jeff
parent
commit
31bba837ca
  1. 52
      src/components/library/AlbumList.tsx
  2. 65
      src/components/library/FolderList.tsx
  3. 91
      src/components/settings/ConfigPanels/ListViewConfig.tsx
  4. 18
      src/components/settings/ConfigPanels/LookAndFeelConfig.tsx
  5. 16
      src/components/settings/ConfigPanels/PlaybackConfig.tsx
  6. 29
      src/components/settings/ConfigPanels/ServerConfig.tsx
  7. 1
      src/components/shared/ContextMenu.tsx
  8. 4
      src/components/shared/styled.ts
  9. 42
      src/components/viewtypes/ViewTypeButtons.tsx
  10. 6
      src/styles/App.global.css
  11. 1
      src/styles/custom-theme.less

52
src/components/library/AlbumList.tsx

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import _ from 'lodash';
import settings from 'electron-settings';
import { ButtonToolbar } from 'rsuite';
@ -18,7 +18,7 @@ import {
toggleRangeSelected,
clearSelected,
} from '../../redux/multiSelectSlice';
import { StyledInputPicker } from '../shared/styled';
import { StyledInputPicker, StyledInputPickerContainer } from '../shared/styled';
import { RefreshButton } from '../shared/ToolbarButtons';
import { setActive } from '../../redux/albumSlice';
@ -42,6 +42,7 @@ const AlbumList = () => {
const [sortTypes, setSortTypes] = useState<any[]>();
const [viewType, setViewType] = useState(settings.getSync('albumViewType'));
const [musicFolder, setMusicFolder] = useState(undefined);
const albumFilterPickerContainerRef = useRef(null);
useEffect(() => {
if (folder.applied.albums) {
@ -150,23 +151,36 @@ const AlbumList = () => {
<GenericPageHeader
title="Albums"
subtitle={
<ButtonToolbar>
<StyledInputPicker
size="sm"
width={180}
defaultValue={album.active.filter}
groupBy="role"
data={sortTypes}
cleanable={false}
placeholder="Sort Type"
onChange={async (value: string) => {
await queryClient.cancelQueries(['albumList', album.active.filter, musicFolder]);
setSearchQuery('');
dispatch(setActive({ ...album.active, filter: value }));
}}
/>
<RefreshButton onClick={handleRefresh} size="sm" loading={isRefreshing} width={100} />
</ButtonToolbar>
<StyledInputPickerContainer ref={albumFilterPickerContainerRef}>
<ButtonToolbar>
<StyledInputPicker
container={() => albumFilterPickerContainerRef.current}
size="sm"
width={180}
defaultValue={album.active.filter}
groupBy="role"
data={sortTypes}
cleanable={false}
placeholder="Sort Type"
onChange={async (value: string) => {
await queryClient.cancelQueries([
'albumList',
album.active.filter,
musicFolder,
]);
setSearchQuery('');
dispatch(setActive({ ...album.active, filter: value }));
}}
/>
<RefreshButton
onClick={handleRefresh}
size="sm"
loading={isRefreshing}
width={100}
/>
</ButtonToolbar>
</StyledInputPickerContainer>
}
subsidetitle={<></>}
searchQuery={searchQuery}

65
src/components/library/FolderList.tsx

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import settings from 'electron-settings';
import _ from 'lodash';
import { useQuery, useQueryClient } from 'react-query';
@ -23,7 +23,7 @@ import {
} from '../../redux/multiSelectSlice';
import GenericPage from '../layout/GenericPage';
import GenericPageHeader from '../layout/GenericPageHeader';
import { StyledButton, StyledInputPicker } from '../shared/styled';
import { StyledButton, StyledInputPicker, StyledInputPickerContainer } from '../shared/styled';
import { fixPlayer2Index, setPlayQueueByRowClick, setRate } from '../../redux/playQueueSlice';
import { setStatus } from '../../redux/playerSlice';
import useSearchQuery from '../../hooks/useSearchQuery';
@ -37,6 +37,7 @@ const FolderList = () => {
const queryClient = useQueryClient();
const folder = useAppSelector((state) => state.folder);
const [musicFolder, setMusicFolder] = useState(folder.musicFolder);
const folderPickerContainerRef = useRef(null);
const { isLoading, isError, data: indexData, error }: any = useQuery(
['indexes', musicFolder],
@ -163,33 +164,39 @@ const FolderList = () => {
showTitleTooltip
subtitle={
<>
<ButtonToolbar>
<StyledInputPicker
data={musicFolders}
defaultValue={musicFolder}
valueKey="id"
labelKey="name"
onChange={(e: any) => {
setMusicFolder(e);
}}
style={{ width: '250px' }}
/>
<StyledButton
size="sm"
onClick={() => {
history.push(
`/library/folder?folderId=${folderData?.parent ? folderData.parent : ''}`
);
dispatch(
setCurrentViewedFolder(folderData?.parent ? folderData.parent : '')
);
}}
>
<Icon icon="level-up" style={{ marginRight: '10px' }} />
Go up
</StyledButton>
</ButtonToolbar>
<StyledInputPickerContainer ref={folderPickerContainerRef}>
<ButtonToolbar>
<StyledInputPicker
container={() => folderPickerContainerRef.current}
size="sm"
width={180}
data={musicFolders}
defaultValue={musicFolder}
valueKey="id"
labelKey="name"
onChange={(e: any) => {
setMusicFolder(e);
}}
/>
<StyledButton
size="sm"
onClick={() => {
history.push(
`/library/folder?folderId=${
folderData?.parent ? folderData.parent : ''
}`
);
dispatch(
setCurrentViewedFolder(folderData?.parent ? folderData.parent : '')
);
}}
>
<Icon icon="level-up" style={{ marginRight: '10px' }} />
Go up
</StyledButton>
</ButtonToolbar>
</StyledInputPickerContainer>
</>
}
/>

91
src/components/settings/ConfigPanels/ListViewConfig.tsx

@ -1,8 +1,13 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { nanoid } from 'nanoid/non-secure';
import settings from 'electron-settings';
import { ControlLabel } from 'rsuite';
import { StyledInputNumber, StyledPanel, StyledTagPicker } from '../../shared/styled';
import {
StyledInputNumber,
StyledInputPickerContainer,
StyledPanel,
StyledTagPicker,
} from '../../shared/styled';
import ListViewTable from '../../viewtypes/ListViewTable';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import {
@ -53,6 +58,7 @@ const ListViewConfig = ({ defaultColumns, columnPicker, columnList, settingsConf
const config = useAppSelector((state) => state.config);
const [selectedColumns, setSelectedColumns] = useState([]);
const columnListType = settingsConfig.columnList.split('List')[0];
const columnPickerContainerRef = useRef(null);
useEffect(() => {
const cols = config.lookAndFeel.listView[columnListType].columns.map((col: any) => {
@ -100,46 +106,49 @@ const ListViewConfig = ({ defaultColumns, columnPicker, columnList, settingsConf
<div style={{ width: '100%' }}>
<div>
<StyledPanel bordered bodyFill>
<StyledTagPicker
data={columnPicker}
defaultValue={defaultColumns}
value={selectedColumns}
style={{ width: '100%' }}
onChange={(e: any) => {
const columns: any[] = [];
if (e) {
e.forEach((selected: string) => {
const alreadySelectedColumn = config.lookAndFeel.listView[
columnListType
].columns.find((column: any) => column.label === selected);
if (alreadySelectedColumn) {
return columns.push(alreadySelectedColumn);
}
const selectedColumn = columnList.find(
(column: any) => column.label === selected
);
if (selectedColumn) {
return columns.push({ ...selectedColumn.value, uniqueId: nanoid() });
}
return null;
<StyledInputPickerContainer ref={columnPickerContainerRef}>
<StyledTagPicker
container={() => columnPickerContainerRef.current}
data={columnPicker}
defaultValue={defaultColumns}
value={selectedColumns}
style={{ width: '100%' }}
onChange={(e: any) => {
const columns: any[] = [];
if (e) {
e.forEach((selected: string) => {
const alreadySelectedColumn = config.lookAndFeel.listView[
columnListType
].columns.find((column: any) => column.label === selected);
if (alreadySelectedColumn) {
return columns.push(alreadySelectedColumn);
}
const selectedColumn = columnList.find(
(column: any) => column.label === selected
);
if (selectedColumn) {
return columns.push({ ...selectedColumn.value, uniqueId: nanoid() });
}
return null;
});
}
const cleanColumns = columns.map((col) => {
const { uniqueId, ...rest } = col;
return rest;
});
}
const cleanColumns = columns.map((col) => {
const { uniqueId, ...rest } = col;
return rest;
});
dispatch(setColumnList({ listType: columnListType, entries: columns }));
settings.setSync(settingsConfig.columnList, cleanColumns);
}}
labelKey="label"
valueKey="label"
/>
dispatch(setColumnList({ listType: columnListType, entries: columns }));
settings.setSync(settingsConfig.columnList, cleanColumns);
}}
labelKey="label"
valueKey="label"
/>
</StyledInputPickerContainer>
<ListViewTable
data={config.lookAndFeel.listView[columnListType].columns || []}

18
src/components/settings/ConfigPanels/LookAndFeelConfig.tsx

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useRef, useState } from 'react';
import settings from 'electron-settings';
import { RadioGroup, ControlLabel, Nav } from 'rsuite';
import { ConfigPanel } from '../styled';
@ -8,6 +8,7 @@ import {
StyledNavItem,
StyledInputNumber,
StyledCheckbox,
StyledInputPickerContainer,
} from '../../shared/styled';
import ListViewConfig from './ListViewConfig';
import { Fonts } from '../Fonts';
@ -36,6 +37,8 @@ const LookAndFeelConfig = () => {
const [highlightOnRowHoverChk, setHighlightOnRowHoverChk] = useState(
Boolean(settings.getSync('highlightOnRowHover'))
);
const fontPickerContainerRef = useRef(null);
const titleBarPickerContainerRef = useRef(null);
const songCols: any = settings.getSync('musicListColumns');
const albumCols: any = settings.getSync('albumListColumns');
@ -67,10 +70,14 @@ const LookAndFeelConfig = () => {
<StyledRadio value="defaultDark">Default Dark</StyledRadio>
<StyledRadio value="defaultLight">Default Light</StyledRadio>
</RadioGroup>
<br />
</div>
<br />
<StyledInputPickerContainer ref={fontPickerContainerRef}>
<ControlLabel>Font</ControlLabel>
<br />
<StyledInputPicker
container={() => fontPickerContainerRef.current}
data={Fonts}
groupBy="role"
cleanable={false}
@ -80,12 +87,13 @@ const LookAndFeelConfig = () => {
dispatch(setFont(e));
}}
/>
</div>
</StyledInputPickerContainer>
<br />
<div>
<StyledInputPickerContainer ref={titleBarPickerContainerRef}>
<ControlLabel>Titlebar style (requires app restart)</ControlLabel>
<br />
<StyledInputPicker
container={() => titleBarPickerContainerRef.current}
data={[
{
label: 'macOS',
@ -103,7 +111,7 @@ const LookAndFeelConfig = () => {
dispatch(setMiscSetting({ setting: 'titleBar', value: e }));
}}
/>
</div>
</StyledInputPickerContainer>
<br />
<StyledCheckbox
defaultChecked={dynamicBackgroundChk}

16
src/components/settings/ConfigPanels/PlaybackConfig.tsx

@ -1,14 +1,21 @@
import React from 'react';
import React, { useRef } from 'react';
import settings from 'electron-settings';
import { ControlLabel, RadioGroup } from 'rsuite';
import { ConfigPanel } from '../styled';
import { StyledInputNumber, StyledInputPicker, StyledRadio } from '../../shared/styled';
import {
StyledInputNumber,
StyledInputPicker,
StyledInputPickerContainer,
StyledRadio,
} from '../../shared/styled';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import { setPlaybackSetting, setPlayerVolume } from '../../../redux/playQueueSlice';
const PlaybackConfig = () => {
const dispatch = useAppDispatch();
const playQueue = useAppSelector((state) => state.playQueue);
const crossfadePickerContainerRef = useRef(null);
return (
<ConfigPanel header="Playback" bordered>
<p>
@ -77,10 +84,11 @@ const PlaybackConfig = () => {
}}
/>
<br />
<div>
<StyledInputPickerContainer ref={crossfadePickerContainerRef}>
<ControlLabel>Crossfade type</ControlLabel>
<br />
<StyledInputPicker
container={() => crossfadePickerContainerRef.current}
data={[
{
label: 'Equal Power',
@ -118,7 +126,7 @@ const PlaybackConfig = () => {
dispatch(setPlaybackSetting({ setting: 'fadeType', value: e }));
}}
/>
</div>
</StyledInputPickerContainer>
<br />
<ControlLabel>Volume fade</ControlLabel>

29
src/components/settings/ConfigPanels/ServerConfig.tsx

@ -1,9 +1,9 @@
import React from 'react';
import React, { useRef } from 'react';
import settings from 'electron-settings';
import { useQuery } from 'react-query';
import { CheckboxGroup } from 'rsuite';
import { ConfigPanel } from '../styled';
import { StyledCheckbox, StyledInputPicker } from '../../shared/styled';
import { StyledCheckbox, StyledInputPicker, StyledInputPickerContainer } from '../../shared/styled';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import { getMusicFolders } from '../../../api/api';
import { setAppliedFolderViews, setMusicFolder } from '../../../redux/folderSlice';
@ -12,21 +12,26 @@ const ServerConfig = () => {
const dispatch = useAppDispatch();
const folder = useAppSelector((state) => state.folder);
const { isLoading, data: musicFolders } = useQuery(['musicFolders'], getMusicFolders);
const musicFolderPickerContainerRef = useRef(null);
return (
<ConfigPanel header="Server" bordered>
<p>Select a music folder (leaving this blank will use all folders).</p>
<br />
<StyledInputPicker
data={isLoading ? [] : musicFolders}
defaultValue={folder.musicFolder}
valueKey="id"
labelKey="name"
onChange={(e: any) => {
settings.setSync('musicFolder.id', e);
dispatch(setMusicFolder(e));
}}
/>
<StyledInputPickerContainer ref={musicFolderPickerContainerRef}>
<StyledInputPicker
container={() => musicFolderPickerContainerRef.current}
data={isLoading ? [] : musicFolders}
defaultValue={folder.musicFolder}
valueKey="id"
labelKey="name"
onChange={(e: any) => {
settings.setSync('musicFolder.id', e);
dispatch(setMusicFolder(e));
}}
/>
</StyledInputPickerContainer>
<div>
<br />
<p>Select which pages to apply music folder filtering to:</p>

1
src/components/shared/ContextMenu.tsx

@ -109,6 +109,7 @@ export const GlobalContextMenu = () => {
const [shouldCreatePlaylist, setShouldCreatePlaylist] = useState(false);
const [newPlaylistName, setNewPlaylistName] = useState('');
const [indexToMoveTo, setIndexToMoveTo] = useState(0);
const playlistPickerContainerRef = useRef(null);
const { data: playlists }: any = useQuery(['playlists', 'name'], () => getPlaylists('name'));

4
src/components/shared/styled.ts

@ -337,10 +337,6 @@ export const StyledInputPicker = styled(InputPicker)<{ width?: number }>`
border-radius: ${(props) => props.theme.other.input.borderRadius};
}
.rs-picker-select-menu-item {
background: ${(props) => `${props.theme.colors.background.input} !important`};
}
.rs-btn-default {
background: ${(props) => `${props.theme.colors.input.background} !important`};
}

42
src/components/viewtypes/ViewTypeButtons.tsx

@ -1,31 +1,31 @@
import React from 'react';
import { ButtonToolbar, ButtonGroup, Icon } from 'rsuite';
import { ButtonToolbar, Icon } from 'rsuite';
import settings from 'electron-settings';
import { StyledIconButton } from '../shared/styled';
const ViewTypeButtons = ({ handleListClick, handleGridClick, viewTypeSetting }: any) => {
return (
<ButtonToolbar>
<ButtonGroup>
<StyledIconButton
icon={<Icon icon="list" />}
appearance="subtle"
onClick={async () => {
handleListClick();
localStorage.setItem(`${viewTypeSetting}ViewType`, 'list');
settings.setSync(`${viewTypeSetting}ViewType`, 'list');
}}
/>
<StyledIconButton
icon={<Icon icon="th-large" />}
appearance="subtle"
onClick={async () => {
handleGridClick();
localStorage.setItem(`${viewTypeSetting}ViewType`, 'grid');
settings.setSync(`${viewTypeSetting}ViewType`, 'grid');
}}
/>
</ButtonGroup>
<StyledIconButton
icon={<Icon icon="list" />}
size="sm"
appearance="subtle"
onClick={async () => {
handleListClick();
localStorage.setItem(`${viewTypeSetting}ViewType`, 'list');
settings.setSync(`${viewTypeSetting}ViewType`, 'list');
}}
/>
<StyledIconButton
icon={<Icon icon="th-large" />}
size="sm"
appearance="subtle"
onClick={async () => {
handleGridClick();
localStorage.setItem(`${viewTypeSetting}ViewType`, 'grid');
settings.setSync(`${viewTypeSetting}ViewType`, 'grid');
}}
/>
</ButtonToolbar>
);
};

6
src/styles/App.global.css

@ -57,6 +57,12 @@ body {
}
*/
/* Fixes the picker menu position */
.rs-picker-menu {
left: inherit !important;
top: inherit !important;
}
*::-webkit-scrollbar {
width: 10px;
}

1
src/styles/custom-theme.less

@ -45,6 +45,7 @@
@table-head-font-color: undefined;
@table-resize-mouse-color: #292d33;
@table-sort-icon-unsort: '';
@zindex-table-header-row-wrapper: 0;
// Sidenav
@sidenav-default-bg: undefined;

Loading…
Cancel
Save