2022-05-29 17:53:27 +08:00
|
|
|
import React, { useEffect, useState } from 'react'
|
|
|
|
import { css, cx } from '@emotion/css'
|
|
|
|
import Icon from '../Icon'
|
2022-06-08 00:07:04 +08:00
|
|
|
import { useLocation, useNavigate } from 'react-router-dom'
|
2022-05-29 17:53:27 +08:00
|
|
|
import { useAnimation, motion } from 'framer-motion'
|
|
|
|
import { ease } from '@/web/utils/const'
|
2022-06-08 00:07:04 +08:00
|
|
|
import TrafficLight from './TrafficLight'
|
|
|
|
import useIsMobile from '@/web/hooks/useIsMobile'
|
2022-05-29 17:53:27 +08:00
|
|
|
|
|
|
|
const tabs = [
|
|
|
|
{
|
|
|
|
name: 'MY MUSIC',
|
|
|
|
path: '/',
|
|
|
|
icon: 'my',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'DISCOVER',
|
|
|
|
path: '/discover',
|
|
|
|
icon: 'explore',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'BROWSE',
|
|
|
|
path: '/browse',
|
|
|
|
icon: 'discovery',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'LYRICS',
|
|
|
|
path: '/lyrics',
|
|
|
|
icon: 'lyrics',
|
|
|
|
},
|
|
|
|
] as const
|
|
|
|
|
|
|
|
const getNameByPath = (path: string): string => {
|
|
|
|
return tabs.find(tab => tab.path === path)?.name || ''
|
|
|
|
}
|
|
|
|
const TabName = () => {
|
|
|
|
const location = useLocation()
|
|
|
|
const [name, setName] = useState(getNameByPath(location.pathname))
|
|
|
|
const controls = useAnimation()
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const newName = getNameByPath(location.pathname)
|
|
|
|
const animate = async () => {
|
|
|
|
await controls.start('out')
|
|
|
|
setName(newName)
|
|
|
|
await controls.start('in')
|
|
|
|
}
|
|
|
|
if (newName !== name) animate()
|
|
|
|
}, [controls, location.pathname, name])
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={cx(
|
|
|
|
'absolute bottom-8 right-0 left-0 z-10 flex rotate-180 select-none items-center font-bold text-brand-600 dark:text-brand-700',
|
|
|
|
css`
|
|
|
|
writing-mode: vertical-rl;
|
|
|
|
text-orientation: mixed;
|
|
|
|
letter-spacing: 0.02em;
|
|
|
|
`
|
|
|
|
)}
|
|
|
|
>
|
|
|
|
<motion.span
|
|
|
|
initial='in'
|
|
|
|
animate={controls}
|
|
|
|
variants={{
|
|
|
|
in: { opacity: 1 },
|
|
|
|
out: { opacity: 0 },
|
|
|
|
}}
|
|
|
|
transition={{
|
|
|
|
duration: 0.18,
|
|
|
|
ease,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
</motion.span>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-06-08 00:07:04 +08:00
|
|
|
const Tabs = () => {
|
|
|
|
const navigate = useNavigate()
|
|
|
|
const controls = useAnimation()
|
2022-06-08 11:48:22 +08:00
|
|
|
const [active, setActive] = useState<string>(tabs[0].path)
|
2022-06-08 00:07:04 +08:00
|
|
|
|
|
|
|
const animate = async (path: string) => {
|
|
|
|
await controls.start((p: string) =>
|
|
|
|
p === path && location.pathname !== path ? 'scale' : 'reset'
|
|
|
|
)
|
|
|
|
await controls.start('reset')
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className='grid grid-cols-4 justify-items-center text-black/10 dark:text-white/20 lg:grid-cols-1 lg:gap-12'>
|
|
|
|
{tabs.map(tab => (
|
|
|
|
<motion.div
|
|
|
|
key={tab.name}
|
|
|
|
animate={controls}
|
|
|
|
transition={{ ease, duration: 0.18 }}
|
|
|
|
onMouseDown={() => animate(tab.path)}
|
2022-06-08 11:48:22 +08:00
|
|
|
onClick={() => {
|
|
|
|
setActive(tab.path)
|
|
|
|
navigate(tab.path)
|
|
|
|
}}
|
2022-06-08 00:07:04 +08:00
|
|
|
custom={tab.path}
|
|
|
|
variants={{
|
|
|
|
scale: { scale: 0.8 },
|
|
|
|
reset: { scale: 1 },
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Icon
|
|
|
|
name={tab.icon}
|
|
|
|
className={cx(
|
|
|
|
'app-region-no-drag h-10 w-10 transition-colors duration-500',
|
2022-06-08 11:48:22 +08:00
|
|
|
active === tab.path
|
2022-06-08 00:07:04 +08:00
|
|
|
? 'text-brand-600 dark:text-brand-700'
|
2022-06-08 11:48:22 +08:00
|
|
|
: 'lg:hover:text-black lg:dark:hover:text-white'
|
2022-06-08 00:07:04 +08:00
|
|
|
)}
|
|
|
|
/>
|
|
|
|
</motion.div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
2022-05-29 17:53:27 +08:00
|
|
|
|
2022-06-08 00:07:04 +08:00
|
|
|
const MenuBar = () => {
|
|
|
|
const isMobile = useIsMobile()
|
2022-05-29 17:53:27 +08:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={cx(
|
|
|
|
'app-region-drag relative flex h-full w-full flex-col justify-center',
|
|
|
|
css`
|
2022-06-08 00:07:04 +08:00
|
|
|
grid-area: menubar;
|
2022-05-29 17:53:27 +08:00
|
|
|
`
|
|
|
|
)}
|
|
|
|
>
|
2022-06-08 00:07:04 +08:00
|
|
|
{window.env?.isMac && (
|
|
|
|
<div className='fixed top-6 left-6 translate-y-0.5'>
|
|
|
|
<TrafficLight />
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
<Tabs />
|
|
|
|
{!isMobile && <TabName />}
|
2022-05-29 17:53:27 +08:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-06-08 00:07:04 +08:00
|
|
|
export default MenuBar
|