Skip to content

Commit

Permalink
next-ui: add active item for sidebar
Browse files Browse the repository at this point in the history
Signed-off-by: Login Victor <batazor@evrone.com>
  • Loading branch information
batazor committed Sep 16, 2022
1 parent ed8f1ae commit 0925c36
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 32 deletions.
66 changes: 66 additions & 0 deletions ui/next/components/Header/ActiveIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useRouter } from 'next/router'
import ListItemIcon, { ListItemIconProps } from "@mui/material/ListItemIcon";
import React, { useState, useEffect, ReactElement, Children } from 'react'
import { UrlObject } from 'url';

declare type Url = string | UrlObject;

type ActiveLinkProps = ListItemIconProps & {
href: Url;
children: ReactElement
activeClassName?: string
}

const ActiveLink = ({
children,
activeClassName,
...props
}: ActiveLinkProps) => {
const { asPath, isReady } = useRouter()

const child = Children.only(children)
const childClassName = child.props.className || ''
const [className, setClassName] = useState(childClassName)

useEffect(() => {
// Check if the router fields are updated client-side
if (isReady) {
// Dynamic route will be matched via props.as
// Static route will be matched via props.href
const linkPathname = new URL(
props.href as string,
location.href
).pathname

// Using URL().pathname to get rid of query and hash
const activePathname = new URL(asPath, location.href).pathname

const newClassName =
linkPathname === activePathname
? `${childClassName} ${activeClassName}`.trim()
: childClassName

if (newClassName !== className) {
setClassName(newClassName)
}
}
}, [
asPath,
isReady,
props.href,
childClassName,
activeClassName,
setClassName,
className,
])

return (
<ListItemIcon {...props}>
{React.cloneElement(child, {
className: className || null,
})}
</ListItemIcon>
)
}

export default ActiveLink
63 changes: 63 additions & 0 deletions ui/next/components/Header/ActiveLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useRouter } from 'next/router'
import Link, { LinkProps } from 'next/link'
import React, { useState, useEffect, ReactElement, Children } from 'react'

type ActiveLinkProps = LinkProps & {
children: ReactElement
activeClassName?: string
}

const ActiveLink = ({
children,
activeClassName,
...props
}: ActiveLinkProps) => {
const { asPath, isReady } = useRouter()

const child = Children.only(children)
const childClassName = child.props.className || ''
const [className, setClassName] = useState(childClassName)

useEffect(() => {
// Check if the router fields are updated client-side
if (isReady) {
// Dynamic route will be matched via props.as
// Static route will be matched via props.href
const linkPathname = new URL(
(props.as || props.href) as string,
location.href
).pathname

// Using URL().pathname to get rid of query and hash
const activePathname = new URL(asPath, location.href).pathname

const newClassName =
linkPathname === activePathname
? `${childClassName} ${activeClassName}`.trim()
: childClassName

if (newClassName !== className) {
setClassName(newClassName)
}
}
}, [
asPath,
isReady,
props.as,
props.href,
childClassName,
activeClassName,
setClassName,
className,
])

return (
<Link {...props}>
{React.cloneElement(child, {
className: className || null,
})}
</Link>
)
}

export default ActiveLink
50 changes: 18 additions & 32 deletions ui/next/components/Header/listItems.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from 'react'
import Link from 'next/link'
import ListItemButton from '@mui/material/ListItemButton'
import Tooltip from '@mui/material/Tooltip'
import ListItemIcon from '@mui/material/ListItemIcon'
import ListItemText from '@mui/material/ListItemText'
import ListSubheader from '@mui/material/ListSubheader'
import DashboardIcon from '@mui/icons-material/Dashboard'
Expand All @@ -16,6 +14,21 @@ import PersonIcon from '@mui/icons-material/Person'
import HttpIcon from '@mui/icons-material/Http'
import PeopleIcon from '@mui/icons-material/People'
import GroupAddIcon from '@mui/icons-material/GroupAdd'
import ActiveLink from './ActiveLink'
import ActiveIcon from './ActiveIcon'

const ListItem = ({ url, icon, name }: any) => (
<ActiveLink href={url} key={url} passHref activeClassName="md:text-blue-700">
<Tooltip title={name} followCursor enterDelay={500}>
<ListItemButton>
<ActiveIcon href={url} activeClassName="md:text-blue-700">
{icon}
</ActiveIcon>
<ListItemText primary={name} />
</ListItemButton>
</Tooltip>
</ActiveLink>
)

const mainMenuList = [
{
Expand Down Expand Up @@ -50,16 +63,7 @@ const mainMenuList = [
},
]

export const mainListItems = mainMenuList.map((item) => (
<Link href={item.url} key={item.url} passHref>
<ListItemButton>
<Tooltip title={item.name}>
<ListItemIcon>{item.icon}</ListItemIcon>
</Tooltip>
<ListItemText primary={item.name} />
</ListItemButton>
</Link>
))
export const mainListItems = mainMenuList.map(item => <ListItem {...item} />)

const otherMenuList = [
{
Expand All @@ -81,16 +85,7 @@ const otherMenuList = [

export const secondaryListItems = [
<ListSubheader inset>Other options</ListSubheader>,
otherMenuList.map((item) => (
<Link href={item.url} key={item.url} passHref>
<ListItemButton>
<Tooltip title={item.name}>
<ListItemIcon>{item.icon}</ListItemIcon>
</Tooltip>
<ListItemText primary={item.name} />
</ListItemButton>
</Link>
)),
otherMenuList.map(item => <ListItem {...item} />),
]

const adminMenuList = [
Expand All @@ -113,14 +108,5 @@ const adminMenuList = [

export const adminListItems = [
<ListSubheader inset>Admin options</ListSubheader>,
adminMenuList.map((item) => (
<Link href={item.url} key={item.url} passHref>
<ListItemButton>
<Tooltip title={item.name}>
<ListItemIcon>{item.icon}</ListItemIcon>
</Tooltip>
<ListItemText primary={item.name} />
</ListItemButton>
</Link>
)),
adminMenuList.map(item => <ListItem {...item} />),
]

0 comments on commit 0925c36

Please sign in to comment.