Convert SideNav to TypeScript
parent
e3529ee636
commit
10ad7f2ab6
|
@ -1,130 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Link} from 'react-router'
|
||||
import classnames from 'classnames'
|
||||
|
||||
const {bool, node, string} = PropTypes
|
||||
|
||||
const NavListItem = React.createClass({
|
||||
propTypes: {
|
||||
link: string.isRequired,
|
||||
children: node,
|
||||
location: string,
|
||||
useAnchor: bool,
|
||||
isExternal: bool,
|
||||
},
|
||||
|
||||
render() {
|
||||
const {link, children, location, useAnchor, isExternal} = this.props
|
||||
const isActive = location.startsWith(link)
|
||||
|
||||
return useAnchor ? (
|
||||
<a
|
||||
className={classnames('sidebar-menu--item', {active: isActive})}
|
||||
href={link}
|
||||
target={isExternal ? '_blank' : '_self'}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
className={classnames('sidebar-menu--item', {active: isActive})}
|
||||
to={link}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
const NavHeader = React.createClass({
|
||||
propTypes: {
|
||||
link: string,
|
||||
title: string,
|
||||
useAnchor: bool,
|
||||
},
|
||||
render() {
|
||||
const {link, title, useAnchor} = this.props
|
||||
|
||||
// Some nav items, such as Logout, need to hit an external link rather
|
||||
// than simply route to an internal page. Anchor tags serve that purpose.
|
||||
return useAnchor ? (
|
||||
<a className="sidebar-menu--heading" href={link}>
|
||||
{title}
|
||||
</a>
|
||||
) : (
|
||||
<Link className="sidebar-menu--heading" to={link}>
|
||||
{title}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
const NavBlock = React.createClass({
|
||||
propTypes: {
|
||||
children: node,
|
||||
link: string,
|
||||
icon: string.isRequired,
|
||||
location: string,
|
||||
className: string,
|
||||
},
|
||||
|
||||
render() {
|
||||
const {location, className} = this.props
|
||||
const isActive = React.Children.toArray(this.props.children).find(child => {
|
||||
return location.startsWith(child.props.link) // if location is undefined, this will fail silently
|
||||
})
|
||||
|
||||
const children = React.Children.map(this.props.children, child => {
|
||||
if (child && child.type === NavListItem) {
|
||||
return React.cloneElement(child, {location})
|
||||
}
|
||||
|
||||
return child
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('sidebar--item', className, {active: isActive})}
|
||||
>
|
||||
{this.renderSquare()}
|
||||
<div className="sidebar-menu">
|
||||
{children}
|
||||
<div className="sidebar-menu--triangle" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
renderSquare() {
|
||||
const {link, icon} = this.props
|
||||
|
||||
if (!link) {
|
||||
return (
|
||||
<div className="sidebar--square">
|
||||
<div className={`sidebar--icon icon ${icon}`} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Link className="sidebar--square" to={link}>
|
||||
<div className={`sidebar--icon icon ${icon}`} />
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
const NavBar = React.createClass({
|
||||
propTypes: {
|
||||
children: node,
|
||||
},
|
||||
|
||||
render() {
|
||||
const {children} = this.props
|
||||
|
||||
return <nav className="sidebar">{children}</nav>
|
||||
},
|
||||
})
|
||||
|
||||
export {NavBar, NavBlock, NavHeader, NavListItem}
|
|
@ -0,0 +1,120 @@
|
|||
import React, {PureComponent, SFC, ReactNode, ReactElement} from 'react'
|
||||
import {Link} from 'react-router'
|
||||
import classnames from 'classnames'
|
||||
|
||||
interface NavListItemProps {
|
||||
link?: string
|
||||
location?: string
|
||||
useAnchor?: boolean
|
||||
isExternal?: boolean
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
const NavListItem: SFC<NavListItemProps> = ({
|
||||
link,
|
||||
children,
|
||||
location,
|
||||
useAnchor,
|
||||
isExternal,
|
||||
}) => {
|
||||
const isActive = location.startsWith(link)
|
||||
return useAnchor ? (
|
||||
<a
|
||||
className={classnames('sidebar-menu--item', {active: isActive})}
|
||||
href={link}
|
||||
target={isExternal ? '_blank' : '_self'}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
className={classnames('sidebar-menu--item', {active: isActive})}
|
||||
to={link}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
interface NavHeaderProps {
|
||||
link?: string
|
||||
title?: string
|
||||
useAnchor?: string
|
||||
}
|
||||
|
||||
const NavHeader: SFC<NavHeaderProps> = ({link, title, useAnchor}) => {
|
||||
// Some nav items, such as Logout, need to hit an external link rather
|
||||
// than simply route to an internal page. Anchor tags serve that purpose.
|
||||
return useAnchor ? (
|
||||
<a className="sidebar-menu--heading" href={link}>
|
||||
{title}
|
||||
</a>
|
||||
) : (
|
||||
<Link className="sidebar-menu--heading" to={link}>
|
||||
{title}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
interface NavBlockProps {
|
||||
children?: ReactNode
|
||||
link?: string
|
||||
icon: string
|
||||
location?: string
|
||||
className?: string
|
||||
matcher?: string
|
||||
}
|
||||
|
||||
class NavBlock extends PureComponent<NavBlockProps> {
|
||||
public render() {
|
||||
const {location, className} = this.props
|
||||
const isActive = React.Children.toArray(this.props.children).find(
|
||||
(child: ReactElement<any>) => {
|
||||
return location.startsWith(child.props.link) // if location is undefined, this will fail silently
|
||||
}
|
||||
)
|
||||
|
||||
const children = React.Children.map(
|
||||
this.props.children,
|
||||
(child: ReactElement<any>) => {
|
||||
if (child && child.type === NavListItem) {
|
||||
return React.cloneElement(child, {location})
|
||||
}
|
||||
|
||||
return child
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('sidebar--item', className, {active: isActive})}
|
||||
>
|
||||
{this.renderSquare()}
|
||||
<div className="sidebar-menu">
|
||||
{children}
|
||||
<div className="sidebar-menu--triangle" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private renderSquare() {
|
||||
const {link, icon} = this.props
|
||||
|
||||
if (!link) {
|
||||
return (
|
||||
<div className="sidebar--square">
|
||||
<div className={`sidebar--icon icon ${icon}`} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Link className="sidebar--square" to={link}>
|
||||
<div className={`sidebar--icon icon ${icon}`} />
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export {NavBlock, NavHeader, NavListItem}
|
|
@ -6,52 +6,13 @@ import Authorized, {ADMIN_ROLE} from 'src/auth/Authorized'
|
|||
|
||||
import UserNavBlock from 'src/side_nav/components/UserNavBlock'
|
||||
import {
|
||||
NavBar,
|
||||
NavBlock,
|
||||
NavHeader,
|
||||
NavListItem,
|
||||
} from 'src/side_nav/components/NavItems'
|
||||
|
||||
import {DEFAULT_HOME_PAGE} from 'src/shared/constants'
|
||||
|
||||
interface Params {
|
||||
sourceID: string
|
||||
}
|
||||
|
||||
interface Location {
|
||||
pathname: string
|
||||
}
|
||||
|
||||
interface ExternalLink {
|
||||
name: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface ExternalLinks {
|
||||
custom: ExternalLink[]
|
||||
}
|
||||
|
||||
interface Links {
|
||||
me?: string
|
||||
external?: ExternalLinks
|
||||
}
|
||||
|
||||
interface Organization {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
interface Role {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
interface Me {
|
||||
name: string
|
||||
currentOrganization: Organization
|
||||
organizations: Organization[]
|
||||
role: Role[]
|
||||
}
|
||||
import {Params, Location, Links, Me} from 'src/types/sideNav'
|
||||
|
||||
interface Props {
|
||||
params: Params
|
||||
|
@ -85,7 +46,7 @@ class SideNav extends PureComponent<Props> {
|
|||
const isDefaultPage = location.split('/').includes(DEFAULT_HOME_PAGE)
|
||||
|
||||
return isHidden ? null : (
|
||||
<NavBar location={location}>
|
||||
<nav className="sidebar">
|
||||
<div
|
||||
className={isDefaultPage ? 'sidebar--item active' : 'sidebar--item'}
|
||||
>
|
||||
|
@ -111,7 +72,7 @@ class SideNav extends PureComponent<Props> {
|
|||
link={`${sourcePrefix}/dashboards`}
|
||||
location={location}
|
||||
>
|
||||
<NavHeader link={`${sourcePrefix}/dashboards`} title={'Dashboards'} />
|
||||
<NavHeader link={`${sourcePrefix}/dashboards`} title="Dashboards" />
|
||||
</NavBlock>
|
||||
<NavBlock
|
||||
matcher="alerts"
|
||||
|
@ -178,7 +139,7 @@ class SideNav extends PureComponent<Props> {
|
|||
sourcePrefix={sourcePrefix}
|
||||
/>
|
||||
) : null}
|
||||
</NavBar>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
export interface Params {
|
||||
sourceID: string
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
pathname: string
|
||||
}
|
||||
|
||||
export interface ExternalLink {
|
||||
name: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface ExternalLinks {
|
||||
custom: ExternalLink[]
|
||||
}
|
||||
|
||||
export interface Links {
|
||||
me?: string
|
||||
external?: ExternalLinks
|
||||
}
|
||||
|
||||
export interface Organization {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface Role {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface Me {
|
||||
name: string
|
||||
currentOrganization: Organization
|
||||
organizations: Organization[]
|
||||
role: Role[]
|
||||
}
|
Loading…
Reference in New Issue