@@ -91,10 +90,10 @@ const Beatmap = ({ theme, beatmap, width }) => {
}
const areEqual = (prevProps, nextProps) => {
- if (prevProps.beatmap.beatmapset_id){
+ if (prevProps.beatmap.beatmapset_id) {
return prevProps.beatmap.beatmapset_id === nextProps.beatmap.beatmapset_id
}
- if (prevProps.beatmap.id){
+ if (prevProps.beatmap.id) {
return prevProps.beatmap.id === nextProps.beatmap.id
}
return false
diff --git a/src/App/components/common/NavPanel/Header.js b/src/App/components/common/NavPanel/Header.js
new file mode 100644
index 00000000..9363934a
--- /dev/null
+++ b/src/App/components/common/NavPanel/Header.js
@@ -0,0 +1,38 @@
+import React from 'react';
+import injectSheet from 'react-jss';
+
+const style = {
+ header: {
+ position: 'relative',
+ height: '48px',
+ display: 'flex',
+ alignItems: 'center',
+ // font-family: "Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif,
+ fontSize: '15px',
+ textTransform: 'uppercase',
+ padding: '0px 24px',
+ overflow: 'hidden',
+ cursor: 'default',
+ userSelect: 'none',
+ color: props => props.theme.dark ? '#fff' : '#000'
+ },
+ divider: {
+ margin: '0 10px',
+ width: '1px',
+ height: '80%',
+ position: 'relative',
+ boxSizing: 'border-box',
+ backgroundColor: 'hsla(0,0%,100%,.1)',
+ }
+};
+const Header = ({ title, classes, children }) => {
+ return (
+
+
{title}
+
+ {children}
+
+ );
+}
+
+export default injectSheet(style)(Header);
\ No newline at end of file
diff --git a/src/App/components/common/NavPanel/Item.js b/src/App/components/common/NavPanel/Item.js
new file mode 100644
index 00000000..5254d93f
--- /dev/null
+++ b/src/App/components/common/NavPanel/Item.js
@@ -0,0 +1,88 @@
+import React, { useState } from 'react'
+import injectSheet from 'react-jss';
+import Header from './Header'
+
+const styles = {
+ contentContainer: {
+ position: 'relative',
+ flexGrow: 1,
+ flexShrink: 1,
+ display: 'flex',
+ },
+ contentSubContainer: {
+ display: 'flex',
+ flex: '1 1 0%',
+ flexDirection: 'column',
+ },
+ content: {
+ display: 'flex',
+ flex: '1 1 0%',
+ flexDirection: 'column',
+ padding: '0px',
+ background: props => props.background,
+ transition: 'background 0ms !important',
+
+ textAlign: 'center',
+ fontSize: 'calc(10px + 2vmin)',
+ color: 'white',
+ backgroundColor: '#121212',
+ textRendering: 'optimizelegibility',
+ fontFamily: 'Open Sans, sans - serif',
+ height: 'calc(100vh - 79px)',
+ overflowY: 'auto',
+
+ '&::-webkit-scrollbar': {
+ width: '8px'
+ },
+ '&::-webkit-scrollbar-track': {
+ background: '#2a2a2a'
+ },
+ '&::-webkit-scrollbar-thumb': {
+ background: '#00965f'
+ }
+
+ }
+};
+
+const Item = ({ classes, color, icon, selected, title, dark, padding, children, background, onSelect, header, theme }) => {
+ //console.log(children)
+ const [headerContent, setHeaderContent] = useState(null);
+ // const lastSection = useRef(title);
+ // useLayoutEffect(() => {
+ // console.log('==============')
+ // console.log('useLayoutEffect', title, lastSection, headerContent, (lastSection.current !== title))
+ // if (headerContent && lastSection.current !== title) {
+ // console.log('RAN')
+ // setHeaderContent(null);
+ // lastSection.current = null;
+ // }
+ // console.log('==============')
+ // return () => lastSection.current = title;
+ // }, [title, headerContent]);
+
+ return (
+
+
+
+ {
+ header ?
+ : null
+ }
+
+
+ {children(setHeaderContent)}
+
+
+
+ );
+}
+
+Item.defaultProps = {
+ title: '',
+ background: '#000',
+ padding: 0,
+}
+
+export default injectSheet(styles)(Item);
\ No newline at end of file
diff --git a/src/App/components/common/NavPanel/SidePanel/Tab.js b/src/App/components/common/NavPanel/SidePanel/Tab.js
new file mode 100644
index 00000000..b976f8b1
--- /dev/null
+++ b/src/App/components/common/NavPanel/SidePanel/Tab.js
@@ -0,0 +1,94 @@
+import React from 'react'
+import injectSheet from 'react-jss';
+
+const styles = {
+ a: {
+ display: 'flex',
+ alignItems: 'center',
+ height: '44px',
+ backgroundColor: 'transparent',
+ cursor: 'pointer',
+ '&:hover': {
+ backgroundColor: 'rgba(255,255,255,0.05)',
+ },
+ '&:hover .indicator': {
+ height: props => props.selected ? '48px' : '24px'
+ },
+ '&:hover .tooltiptext': {
+ visibility: props => props.expended ? 'hidden' : 'visible',
+ }
+
+ },
+ span: {
+ display: 'flex',
+ alignItems: 'center',
+ color: 'rgb(255, 255, 255)',
+ fontSize: '15px',
+ letterSpacing: '0.4pt',
+ padding: '0px 16px',
+ transition: 'transform 0.1s ease-in 0s',
+ userSelect: 'none',
+ },
+ i: {
+ marginRight: '8px',
+ height: '44px',
+ display: 'flex',
+ alignItems: 'center',
+
+ },
+ indicator: {
+ position: 'absolute',
+ left: 0,
+ margin: 0,
+ height: props => props.selected ? '40px' : '0px',
+ width: '3px',
+ backgroundColor: props => props.theme.color,
+ },
+ title: {
+ visibility: props => props.expended ? 'visible' : 'hidden'
+ },
+ tooltiptext: {
+ visibility: 'hidden',
+ width: '120px',
+ backgroundColor: '#2a2a2a',
+ color: '#fff',
+ textAlign: 'center',
+ padding: '5px 0',
+ borderRadius: '6px',
+ position: 'absolute',
+ left: '105%',
+ zIndex: 1,
+ },
+};
+
+const Tab = ({ classes, selected, icon, title, onSelect }) => {
+ return (
+
+ {title}
+
+
+
+ {icon}
+
+
+ {title}
+
+
+
+ );
+}
+
+export default injectSheet(styles)(Tab);
\ No newline at end of file
diff --git a/src/App/components/common/NavPanel/SidePanel/TasksControl.js b/src/App/components/common/NavPanel/SidePanel/TasksControl.js
new file mode 100644
index 00000000..5ddfc582
--- /dev/null
+++ b/src/App/components/common/NavPanel/SidePanel/TasksControl.js
@@ -0,0 +1,161 @@
+import React, { useContext } from 'react'
+import injectSheet from 'react-jss';
+import renderIcons from '../../../../utils/renderIcons';
+import { TasksContext } from '../../../../../Providers/TasksProvider';
+import store from '../../../../../store';
+
+const styles = {
+ '@keyframes spin': {
+ from: {
+ transform: 'rotate(0deg)'
+ },
+ to: {
+ transform: 'rotate(359deg)'
+ }
+ },
+ a: {
+ margin: 'auto 0 0 0',
+ display: 'flex',
+ alignItems: 'center',
+ // height: '44px',
+ minHeight: '44px',
+ backgroundColor: 'transparent',
+ cursor: 'pointer',
+ '&:hover': {
+ backgroundColor: 'rgba(255,255,255,0.05)',
+ },
+ ' &:active': {
+ backgroundColor: 'rgba(255,255,255,0.05)',
+ },
+ '&:hover .indicator': {
+ height: props => props.selected ? '48px' : '24px'
+ },
+ '&:active .indicator': {
+ height: props => props.selected ? '48px' : '24px'
+ },
+ '&:hover .tooltiptext': {
+ visibility: props => props.expended ? 'none' : 'visible',
+ },
+ '&:active .tooltiptext': {
+ visibility: props => props.expended ? 'none' : 'visible',
+ }
+
+ },
+ span: {
+ display: 'flex',
+ alignItems: 'center',
+ color: 'rgb(255, 255, 255)',
+ fontSize: '15px',
+ letterSpacing: '0.4pt',
+ padding: '0px 16px',
+ transition: 'transform 0.1s ease-in 0s',
+ userSelect: 'none',
+ },
+ i: {
+ margin: 'auto 8px 0px 0px',
+ height: '44px',
+ display: 'flex',
+ alignItems: 'center',
+ '& svg': {
+ animation: 'spin 3000ms infinite linear'
+ }
+ },
+ indicator: {
+ position: 'absolute',
+ left: 0,
+ bottom: 98,
+ margin: 0,
+ height: props => props.selected ? '40px' : '0px',
+ width: '3px',
+ backgroundColor: props => props.theme.color,
+ },
+ title: {
+ visibility: props => props.expended ? 'visible' : 'hidden'
+ },
+ tooltiptext: {
+ width: '120px',
+ backgroundColor: '#2a2a2a',
+ color: '#fff',
+ borderRadius: '6px',
+ position: 'absolute',
+ left: '100%',
+ zIndex: 1,
+ textAlign: 'left',
+ padding: '0 0.6rem',
+ visibility: props => props.pop ? 'visible' : 'hidden',
+ },
+ divider: {
+ width: '80px',
+ height: '1px',
+ backgroundColor: 'rgba(255,255,255, 0.05)',
+ }
+
+};
+
+const TasksControl = ({ classes, onSelect, theme }) => {
+ const { tasks } = useContext(TasksContext)
+ const tasksKeys = Object.keys(tasks);
+ const active = tasksKeys.length > 0
+ const renderContent = () => {
+ if (active) return(
+
+ {tasksKeys.map(task => (
+
store.dispatch({type: 'UPDATEACTIVESECTION', payload: tasks[task].section})}>
+
+
{tasks[task].name}
+
+
{tasks[task].description}
+
{tasks[task].description1}
+
+
+
+ ))}
+ {/* {lastTask.name ?
+
+
{lastTask.name}
+
+
Terminated
+
{lastTask.description}
+
+
: null
+
+ } */}
+
+ )}
+ return (
+
+
+ {renderContent()}
+
+
+
+
+ {renderIcons('Loading', theme.style)}
+
+
+ {renderContent()}
+
+
+
+ );
+}
+
+TasksControl.defaultProps = {
+ pop: false
+}
+
+export default injectSheet(styles)(TasksControl);
\ No newline at end of file
diff --git a/src/App/components/common/NavPanel/SidePanel/VolumeControl.js b/src/App/components/common/NavPanel/SidePanel/VolumeControl.js
new file mode 100644
index 00000000..cb76ea06
--- /dev/null
+++ b/src/App/components/common/NavPanel/SidePanel/VolumeControl.js
@@ -0,0 +1,115 @@
+import React, { useState } from 'react'
+import injectSheet from 'react-jss';
+import renderIcons from '../../../../utils/renderIcons';
+import Volume from '../../../Settings/Volume';
+
+const styles = {
+ a: {
+ margin: '0 0 0 0',
+ display: 'flex',
+ alignItems: 'center',
+ height: '44px',
+ backgroundColor: 'transparent',
+ cursor: 'pointer',
+ '&:hover': {
+ backgroundColor: 'rgba(255,255,255,0.05)',
+ },
+ ' &:active': {
+ backgroundColor: 'rgba(255,255,255,0.05)',
+ },
+ '&:hover .indicator': {
+ height: props => props.selected ? '48px' : '24px'
+ },
+ '&:active .indicator': {
+ height: props => props.selected ? '48px' : '24px'
+ },
+ '&:hover .tooltiptext': {
+ visibility: props => props.expended ? 'hidden' : 'visible',
+ },
+ '&:active .tooltiptext': {
+ visibility: props => props.expended ? 'hidden' : 'visible',
+ }
+
+ },
+ span: {
+ display: 'flex',
+ alignItems: 'center',
+ color: 'rgb(255, 255, 255)',
+ fontSize: '15px',
+ letterSpacing: '0.4pt',
+ padding: '0px 16px',
+ transition: 'transform 0.1s ease-in 0s',
+ userSelect: 'none',
+ },
+ i: {
+ marginRight: '8px',
+ height: '44px',
+ display: 'flex',
+ alignItems: 'center',
+ },
+ indicator: {
+ position: 'absolute',
+ left: 0,
+ margin: 0,
+ height: props => props.selected ? '40px' : '0px',
+ width: '3px',
+ backgroundColor: props => props.theme.color,
+ },
+ title: {
+ visibility: props => props.expended ? 'visible' : 'hidden'
+ },
+ tooltiptext: {
+ visibility: 'hidden',
+ width: '120px',
+ backgroundColor: '#2a2a2a',
+ color: '#fff',
+ textAlign: 'center',
+ padding: '5px 0',
+ borderRadius: '6px',
+ position: 'absolute',
+ left: '100%',
+ zIndex: 1,
+ },
+
+};
+
+const VolumeControl = ({ classes, onSelect, theme }) => {
+ const [volumeValue, setVolumeValue] = useState()
+ const updateIcon = () => {
+ if (volumeValue < 1) return renderIcons('VolumeMute', theme.style)
+ if (volumeValue < 35) return renderIcons('VolumeLow', theme.style)
+ if (volumeValue < 75) return renderIcons('VolumeMid', theme.style)
+ return renderIcons('VolumeHigh', theme.style)
+ }
+ return (
+
+
+
+
+
+
+
+ {updateIcon()}
+
+
+
+
+
+
+ );
+}
+
+export default injectSheet(styles)(VolumeControl);
\ No newline at end of file
diff --git a/src/App/components/common/NavPanel/SidePanel/index.js b/src/App/components/common/NavPanel/SidePanel/index.js
new file mode 100644
index 00000000..f61b5646
--- /dev/null
+++ b/src/App/components/common/NavPanel/SidePanel/index.js
@@ -0,0 +1,76 @@
+import React from 'react'
+import injectSheet from 'react-jss';
+import Tab from './Tab';
+import VolumeControl from './VolumeControl';
+import TasksControl from './TasksControl';
+
+const styles = {
+ SidePanel: {
+ cursor: 'default',
+ userSelect: 'none',
+ display: 'flex',
+ position: 'relative',
+ flexGrow: 0,
+ flexShrink: 0,
+ flexDirection: 'column',
+ overflow: 'visible',
+ width: props => props.expended ? props.panelExpandedLength : props.panelCompactedLength,
+ backgroundColor: props => props.background,
+ },
+ head: {
+ height: 48
+ },
+ svg: {
+ position: 'absolute',
+ padding: '8px 10px',
+ top: '7px',
+ left: '4px',
+ width: '20px',
+ height: '20px',
+ cursor: 'pointer',
+
+ },
+};
+
+const SidePanel = ({ classes, color, dark, items, panelExpandedLength, panelCompactedLength, expended, expendable, volume, tasks, setExpended, theme, background }) => {
+ const itemTab = () => items.map((item, i) => {
+ if (items.length - i === 1) return (
+
+ { tasks ? : null }
+ { volume ? : null}
+
+
+ )
+ return
+ })
+
+ return (
+
+ {
+ expendable ?
+
+
+
+ : null
+ }
+ {itemTab()}
+
+ );
+}
+
+export default injectSheet(styles)(SidePanel);
\ No newline at end of file
diff --git a/src/App/components/common/NavPanel/index.js b/src/App/components/common/NavPanel/index.js
new file mode 100644
index 00000000..cabd0d86
--- /dev/null
+++ b/src/App/components/common/NavPanel/index.js
@@ -0,0 +1,44 @@
+import React, { useState } from 'react';
+import injectSheet from 'react-jss';
+import SidePanel from './SidePanel';
+
+const styles = {
+ NavPanel: {
+ display: 'flex',
+ flexWrap: 'nowrap',
+ position: 'relative',
+ flex: '1 1 0%',
+ }
+};
+
+const NavPanel = ({ classes, panelExpandedLength, panelCompactedLength, defaultIsPanelExpanded, expendable, volume, tasks, sidePanelBackground, dark, color, children, theme, onExpended }) => {
+ const [isExpended, setIsExpended] = useState(defaultIsPanelExpanded);
+ return (
+
+ { setIsExpended(expended); onExpended(expended) }}
+ defaultIsPanelExpanded={defaultIsPanelExpanded}
+ panelCompactedLength={panelCompactedLength}
+ panelExpandedLength={panelExpandedLength}
+ expendable={expendable}
+ background={sidePanelBackground}
+ volume={volume}
+ tasks={tasks}
+ />
+
+ {children.filter(child => child.props.selected)}
+
+
+ );
+}
+
+NavPanel.defaultProps = {
+ panelExpandedLength: 150,
+ panelCompactedLength: 48,
+ defaultIsPanelExpanded: false
+}
+
+export default injectSheet(styles)(NavPanel);
diff --git a/src/App/components/common/RangeSlider.js b/src/App/components/common/RangeSlider.js
new file mode 100644
index 00000000..3bfda6e6
--- /dev/null
+++ b/src/App/components/common/RangeSlider.js
@@ -0,0 +1,45 @@
+import React from 'react'
+import injectSheet from 'react-jss';
+import convertRange from '../../utils/convertRange';
+
+const styles = {
+ slider: {
+ '-webkit-appearance': 'none',
+ width: props => props.width || '100%',
+ height: '10px',
+ borderRadius: '5px',
+ //background: '#d7dcdf',
+ outline: 'none',
+ padding: 0,
+ margin: 0,
+ background: props => `linear-gradient(90deg, ${props.theme.color} ${convertRange(props.value, props.min, props.max, 0, 100)}%, #3a3a3a ${convertRange(props.value, props.min, props.max, 0, 100)}%)`,
+ '&::-webkit-slider-thumb': {
+
+ appearance: 'none',
+ width: '20px',
+ height: '20px',
+ borderRadius: '50%',
+ background: props => props.theme.secondary || '#2a2a2a',
+ cursor: 'pointer',
+ transition: 'background .15s ease-in-out',
+
+ '&:hover': {
+ background: props => props.theme.color,
+ }
+ },
+ '&:active::-webkit-slider-thumb': {
+ background: props => props.theme.color,
+ },
+ '&:focus::-webkit-slider-thumb': {
+ //boxShadow: props => `0 0 0 3px #2a2a2a, 0 0 0 6px ${props.theme.color}`,
+ }
+ }
+};
+
+const RangeSlider = ({ classes, value, min, max, onChange }) => {
+ return (
+
+ );
+}
+
+export default injectSheet(styles)(RangeSlider);
\ No newline at end of file
diff --git a/src/App/components/common/Toggle.js b/src/App/components/common/Toggle.js
new file mode 100644
index 00000000..3e5ec76c
--- /dev/null
+++ b/src/App/components/common/Toggle.js
@@ -0,0 +1,48 @@
+import React from 'react';
+import injectSheet from 'react-jss';
+
+const styles = {
+ Toggle: {
+ position: 'relative',
+ display: 'inline-block',
+ width: props => props.width || '40px',
+ height: props => props.height ||'20px',
+ borderRadius: '25px',
+ margin: props => props.margin,
+ // backgroundColor: '#989898',
+ backgroundColor: props => props.checked ? props.theme.color : props.background || '#2a2a2a',
+ opacity: props => props.disabled ? 0.5 : 1
+ },
+ input: {
+ display: 'none'
+ },
+ div: {
+ position: 'absolute',
+ borderRadius: "50%",
+ backgroundColor: '#DFDFDF',
+ transition: '.1s ease',
+ width: '18px',
+ height: '18px',
+ top: '1px',
+ left: props => props.checked ? '50%' : '1px',
+ }
+};
+
+const Toggle = ({ classes, onChange, checked, disabled }) => {
+ return (
+
+ );
+}
+
+export default injectSheet(styles)(Toggle);
\ No newline at end of file
diff --git a/src/App/index.js b/src/App/index.js
index 3c7628f3..a71fd95b 100644
--- a/src/App/index.js
+++ b/src/App/index.js
@@ -18,8 +18,6 @@ const App = ({ theme }) => {
onCloseClick={() => window.close()}
onMaximizeClick={() => window.isMaximized() ? window.unmaximize() : window.maximize()}
onMinimizeClick={() => window.minimize()}
- onMouseDown={() => window.setOpacity(0.70)}
- onMouseUp={() => window.setOpacity(1)}
/>