mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-15 09:33:52 -07:00
Initial Commit Rework
This commit is contained in:
parent
74a4cc048c
commit
95051cbd63
2483 changed files with 101351 additions and 111396 deletions
9
frontend/src/Components/Menu/FilterMenu.css
Normal file
9
frontend/src/Components/Menu/FilterMenu.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
.filterMenu {
|
||||
composes: menu from './Menu.css';
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $breakpointSmall) {
|
||||
.filterMenu {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
44
frontend/src/Components/Menu/FilterMenu.js
Normal file
44
frontend/src/Components/Menu/FilterMenu.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import Menu from 'Components/Menu/Menu';
|
||||
import ToolbarMenuButton from 'Components/Menu/ToolbarMenuButton';
|
||||
import styles from './FilterMenu.css';
|
||||
|
||||
class FilterMenu extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Menu
|
||||
className={className}
|
||||
{...otherProps}
|
||||
>
|
||||
<ToolbarMenuButton
|
||||
iconName={icons.FILTER}
|
||||
text="Filter"
|
||||
/>
|
||||
{children}
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FilterMenu.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
FilterMenu.defaultProps = {
|
||||
className: styles.filterMenu
|
||||
};
|
||||
|
||||
export default FilterMenu;
|
57
frontend/src/Components/Menu/FilterMenuItem.js
Normal file
57
frontend/src/Components/Menu/FilterMenuItem.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import SelectedMenuItem from './SelectedMenuItem';
|
||||
|
||||
class FilterMenuItem extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onPress = () => {
|
||||
const {
|
||||
name,
|
||||
value,
|
||||
onPress
|
||||
} = this.props;
|
||||
|
||||
onPress(name, value);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
value,
|
||||
filterKey,
|
||||
filterValue,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const isSelected = name === filterKey && value === filterValue;
|
||||
|
||||
return (
|
||||
<SelectedMenuItem
|
||||
isSelected={isSelected}
|
||||
{...otherProps}
|
||||
onPress={this.onPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FilterMenuItem.propTypes = {
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
|
||||
filterKey: PropTypes.string,
|
||||
filterValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
|
||||
onPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
FilterMenuItem.defaultProps = {
|
||||
name: null,
|
||||
value: null
|
||||
};
|
||||
|
||||
export default FilterMenuItem;
|
7
frontend/src/Components/Menu/Menu.css
Normal file
7
frontend/src/Components/Menu/Menu.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
.tether {
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.menu {
|
||||
position: relative;
|
||||
}
|
203
frontend/src/Components/Menu/Menu.js
Normal file
203
frontend/src/Components/Menu/Menu.js
Normal file
|
@ -0,0 +1,203 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import TetherComponent from 'react-tether';
|
||||
import { align } from 'Helpers/Props';
|
||||
import styles from './Menu.css';
|
||||
|
||||
const baseTetherOptions = {
|
||||
skipMoveElement: true,
|
||||
constraints: [
|
||||
{
|
||||
to: 'window',
|
||||
attachment: 'together',
|
||||
pin: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const tetherOptions = {
|
||||
[align.RIGHT]: {
|
||||
...baseTetherOptions,
|
||||
attachment: 'top right',
|
||||
targetAttachment: 'bottom right'
|
||||
},
|
||||
|
||||
[align.LEFT]: {
|
||||
...baseTetherOptions,
|
||||
attachment: 'top left',
|
||||
targetAttachment: 'bottom left'
|
||||
}
|
||||
};
|
||||
|
||||
class Menu extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isMenuOpen: false,
|
||||
maxHeight: 0
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setMaxHeight();
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
getMaxHeight() {
|
||||
if (!this.props.enforceMaxHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
const menu = ReactDOM.findDOMNode(this.refs.menu);
|
||||
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { bottom } = menu.getBoundingClientRect();
|
||||
const maxHeight = window.innerHeight - bottom;
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
setMaxHeight() {
|
||||
this.setState({
|
||||
maxHeight: this.getMaxHeight()
|
||||
});
|
||||
}
|
||||
|
||||
_addListener() {
|
||||
// Listen to resize events on the window and scroll events
|
||||
// on all elements to ensure the menu is the best size possible.
|
||||
// Listen for click events on the window to support closing the
|
||||
// menu on clicks outside.
|
||||
|
||||
window.addEventListener('resize', this.onWindowResize);
|
||||
window.addEventListener('scroll', this.onWindowScroll, { capture: true });
|
||||
window.addEventListener('click', this.onWindowClick);
|
||||
}
|
||||
|
||||
_removeListener() {
|
||||
window.removeEventListener('resize', this.onWindowResize);
|
||||
window.removeEventListener('scroll', this.onWindowScroll, { capture: true });
|
||||
window.removeEventListener('click', this.onWindowClick);
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onWindowClick = (event) => {
|
||||
const menu = ReactDOM.findDOMNode(this.refs.menu);
|
||||
const menuContent = ReactDOM.findDOMNode(this.refs.menuContent);
|
||||
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!menu.contains(event.target) || menuContent.contains(event.target)) && this.state.isMenuOpen) {
|
||||
this.setState({ isMenuOpen: false });
|
||||
this._removeListener();
|
||||
}
|
||||
}
|
||||
|
||||
onWindowResize = () => {
|
||||
this.setMaxHeight();
|
||||
}
|
||||
|
||||
onWindowScroll = () => {
|
||||
this.setMaxHeight();
|
||||
}
|
||||
|
||||
onMenuButtonPress = () => {
|
||||
const state = {
|
||||
isMenuOpen: !this.state.isMenuOpen
|
||||
};
|
||||
|
||||
if (this.state.isMenuOpen) {
|
||||
this._removeListener();
|
||||
} else {
|
||||
state.maxHeight = this.getMaxHeight();
|
||||
this._addListener();
|
||||
}
|
||||
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
alignMenu
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
maxHeight,
|
||||
isMenuOpen
|
||||
} = this.state;
|
||||
|
||||
const childrenArray = React.Children.toArray(children);
|
||||
const button = React.cloneElement(
|
||||
childrenArray[0],
|
||||
{
|
||||
onPress: this.onMenuButtonPress
|
||||
}
|
||||
);
|
||||
|
||||
const content = React.cloneElement(
|
||||
childrenArray[1],
|
||||
{
|
||||
ref: 'menuContent',
|
||||
alignMenu,
|
||||
maxHeight,
|
||||
isOpen: isMenuOpen
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<TetherComponent
|
||||
classes={{
|
||||
element: styles.tether
|
||||
}}
|
||||
{...tetherOptions[alignMenu]}
|
||||
>
|
||||
<div
|
||||
ref="menu"
|
||||
className={className}
|
||||
>
|
||||
{button}
|
||||
</div>
|
||||
|
||||
{
|
||||
isMenuOpen &&
|
||||
content
|
||||
}
|
||||
</TetherComponent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Menu.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired,
|
||||
alignMenu: PropTypes.oneOf([align.LEFT, align.RIGHT]),
|
||||
enforceMaxHeight: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
Menu.defaultProps = {
|
||||
className: styles.menu,
|
||||
alignMenu: align.LEFT,
|
||||
enforceMaxHeight: true
|
||||
};
|
||||
|
||||
export default Menu;
|
15
frontend/src/Components/Menu/MenuButton.css
Normal file
15
frontend/src/Components/Menu/MenuButton.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
.menuButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
&::after {
|
||||
margin-left: 5px;
|
||||
content: '\25BE';
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $toobarButtonHoverColor;
|
||||
}
|
||||
}
|
41
frontend/src/Components/Menu/MenuButton.js
Normal file
41
frontend/src/Components/Menu/MenuButton.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import styles from './MenuButton.css';
|
||||
|
||||
class MenuButton extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
onPress,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={className}
|
||||
onPress={onPress}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MenuButton.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired,
|
||||
onPress: PropTypes.func
|
||||
};
|
||||
|
||||
MenuButton.defaultProps = {
|
||||
className: styles.menuButton
|
||||
};
|
||||
|
||||
export default MenuButton;
|
11
frontend/src/Components/Menu/MenuContent.css
Normal file
11
frontend/src/Components/Menu/MenuContent.css
Normal file
|
@ -0,0 +1,11 @@
|
|||
.menuContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: $toolbarMenuItemBackgroundColor;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
43
frontend/src/Components/Menu/MenuContent.js
Normal file
43
frontend/src/Components/Menu/MenuContent.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Scroller from 'Components/Scroller/Scroller';
|
||||
import styles from './MenuContent.css';
|
||||
|
||||
class MenuContent extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
maxHeight
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={{
|
||||
maxHeight: maxHeight ? `${maxHeight}px` : undefined
|
||||
}}
|
||||
>
|
||||
<Scroller className={styles.scroller}>
|
||||
{children}
|
||||
</Scroller>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MenuContent.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired,
|
||||
maxHeight: PropTypes.number
|
||||
};
|
||||
|
||||
MenuContent.defaultProps = {
|
||||
className: styles.menuContent
|
||||
};
|
||||
|
||||
export default MenuContent;
|
19
frontend/src/Components/Menu/MenuItem.css
Normal file
19
frontend/src/Components/Menu/MenuItem.css
Normal file
|
@ -0,0 +1,19 @@
|
|||
.menuItem {
|
||||
composes: truncate from 'Styles/mixins/truncate.css';
|
||||
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
padding: 10px 20px;
|
||||
min-width: 150px;
|
||||
max-width: 250px;
|
||||
background-color: $toolbarMenuItemBackgroundColor;
|
||||
color: $menuItemColor;
|
||||
line-height: 20px;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $toolbarMenuItemHoverBackgroundColor;
|
||||
color: $menuItemHoverColor;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
38
frontend/src/Components/Menu/MenuItem.js
Normal file
38
frontend/src/Components/Menu/MenuItem.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import styles from './MenuItem.css';
|
||||
|
||||
class MenuItem extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={className}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
MenuItem.defaultProps = {
|
||||
className: styles.menuItem
|
||||
};
|
||||
|
||||
export default MenuItem;
|
15
frontend/src/Components/Menu/SelectedMenuItem.css
Normal file
15
frontend/src/Components/Menu/SelectedMenuItem.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
.item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.isSelected {
|
||||
visibility: visible;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.isNotSelected {
|
||||
visibility: hidden;
|
||||
margin-left: 20px;
|
||||
}
|
63
frontend/src/Components/Menu/SelectedMenuItem.js
Normal file
63
frontend/src/Components/Menu/SelectedMenuItem.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import Icon from 'Components/Icon';
|
||||
import MenuItem from './MenuItem';
|
||||
import styles from './SelectedMenuItem.css';
|
||||
|
||||
class SelectedMenuItem extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onPress = () => {
|
||||
const {
|
||||
name,
|
||||
onPress
|
||||
} = this.props;
|
||||
|
||||
onPress(name);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
selectedIconName,
|
||||
isSelected,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
{...otherProps}
|
||||
onPress={this.onPress}
|
||||
>
|
||||
<div className={styles.item}>
|
||||
{children}
|
||||
|
||||
<Icon
|
||||
className={isSelected ? styles.isSelected : styles.isNotSelected}
|
||||
name={selectedIconName}
|
||||
/>
|
||||
</div>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectedMenuItem.propTypes = {
|
||||
name: PropTypes.string,
|
||||
children: PropTypes.node.isRequired,
|
||||
selectedIconName: PropTypes.string.isRequired,
|
||||
isSelected: PropTypes.bool.isRequired,
|
||||
onPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
SelectedMenuItem.defaultProps = {
|
||||
selectedIconName: icons.CHECK
|
||||
};
|
||||
|
||||
export default SelectedMenuItem;
|
39
frontend/src/Components/Menu/SortMenu.js
Normal file
39
frontend/src/Components/Menu/SortMenu.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import Menu from 'Components/Menu/Menu';
|
||||
import ToolbarMenuButton from 'Components/Menu/ToolbarMenuButton';
|
||||
|
||||
class SortMenu extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Menu
|
||||
className={className}
|
||||
{...otherProps}
|
||||
>
|
||||
<ToolbarMenuButton
|
||||
iconName={icons.SORT}
|
||||
text="Sort"
|
||||
/>
|
||||
{children}
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SortMenu.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
export default SortMenu;
|
37
frontend/src/Components/Menu/SortMenuItem.js
Normal file
37
frontend/src/Components/Menu/SortMenuItem.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { icons, sortDirections } from 'Helpers/Props';
|
||||
import SelectedMenuItem from './SelectedMenuItem';
|
||||
|
||||
function SortMenuItem(props) {
|
||||
const {
|
||||
name,
|
||||
sortKey,
|
||||
sortDirection,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const isSelected = name === sortKey;
|
||||
|
||||
return (
|
||||
<SelectedMenuItem
|
||||
name={name}
|
||||
selectedIconName={sortDirection === sortDirections.ASCENDING ? icons.SORT_ASCENDING : icons.SORT_DESCENDING}
|
||||
isSelected={isSelected}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
SortMenuItem.propTypes = {
|
||||
name: PropTypes.string,
|
||||
sortKey: PropTypes.string,
|
||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
||||
onPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
SortMenuItem.defaultProps = {
|
||||
name: null
|
||||
};
|
||||
|
||||
export default SortMenuItem;
|
13
frontend/src/Components/Menu/ToolbarMenuButton.css
Normal file
13
frontend/src/Components/Menu/ToolbarMenuButton.css
Normal file
|
@ -0,0 +1,13 @@
|
|||
.menuButton {
|
||||
composes: menuButton from './MenuButton.css';
|
||||
|
||||
width: $toolbarButtonWidth;
|
||||
height: $toolbarHeight;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
height: 14px;
|
||||
color: $toolbarLabelColor;
|
||||
font-size: $extraSmallFontSize;
|
||||
}
|
38
frontend/src/Components/Menu/ToolbarMenuButton.js
Normal file
38
frontend/src/Components/Menu/ToolbarMenuButton.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import MenuButton from 'Components/Menu/MenuButton';
|
||||
import styles from './ToolbarMenuButton.css';
|
||||
|
||||
function ToolbarMenuButton(props) {
|
||||
const {
|
||||
iconName,
|
||||
text,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<MenuButton
|
||||
className={styles.menuButton}
|
||||
{...otherProps}
|
||||
>
|
||||
<div>
|
||||
<Icon
|
||||
name={iconName}
|
||||
size={22}
|
||||
/>
|
||||
|
||||
<div className={styles.label}>
|
||||
{text}
|
||||
</div>
|
||||
</div>
|
||||
</MenuButton>
|
||||
);
|
||||
}
|
||||
|
||||
ToolbarMenuButton.propTypes = {
|
||||
iconName: PropTypes.string.isRequired,
|
||||
text: PropTypes.string
|
||||
};
|
||||
|
||||
export default ToolbarMenuButton;
|
30
frontend/src/Components/Menu/ViewMenu.js
Normal file
30
frontend/src/Components/Menu/ViewMenu.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import Menu from 'Components/Menu/Menu';
|
||||
import ToolbarMenuButton from 'Components/Menu/ToolbarMenuButton';
|
||||
|
||||
function ViewMenu(props) {
|
||||
const {
|
||||
children,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Menu
|
||||
{...otherProps}
|
||||
>
|
||||
<ToolbarMenuButton
|
||||
iconName={icons.VIEW}
|
||||
text="View"
|
||||
/>
|
||||
{children}
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
ViewMenu.propTypes = {
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
export default ViewMenu;
|
28
frontend/src/Components/Menu/ViewMenuItem.js
Normal file
28
frontend/src/Components/Menu/ViewMenuItem.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import SelectedMenuItem from './SelectedMenuItem';
|
||||
|
||||
function ViewMenuItem(props) {
|
||||
const {
|
||||
name,
|
||||
selectedView,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const isSelected = name === selectedView;
|
||||
|
||||
return (
|
||||
<SelectedMenuItem
|
||||
name={name}
|
||||
isSelected={isSelected}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
ViewMenuItem.propTypes = {
|
||||
name: PropTypes.string,
|
||||
selectedView: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default ViewMenuItem;
|
Loading…
Add table
Add a link
Reference in a new issue