feat: Implement Dropdown and Menu components for breadcrumb navigation in Online Drive
parent
1ff608dfa9
commit
1bd664e655
@ -0,0 +1,61 @@
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import cn from '@/utils/classnames'
|
||||
import Menu from './menu'
|
||||
|
||||
type DropdownProps = {
|
||||
startIndex: number
|
||||
breadcrumbs: string[]
|
||||
onBreadcrumbClick: (index: number) => void
|
||||
}
|
||||
|
||||
const Dropdown = ({
|
||||
startIndex,
|
||||
breadcrumbs,
|
||||
onBreadcrumbClick,
|
||||
}: DropdownProps) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleTrigger = useCallback(() => {
|
||||
setOpen(prev => !prev)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-start'
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
crossAxis: -13,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={handleTrigger}>
|
||||
<button
|
||||
type='button'
|
||||
className={cn(
|
||||
'rounded-md p-1',
|
||||
open ? 'bg-state-base-hover' : 'hover:bg-state-base-hover',
|
||||
)}
|
||||
>
|
||||
<RiMoreFill className='size-4 text-text-tertiary' />
|
||||
</button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[11]'>
|
||||
<Menu
|
||||
breadcrumbs={breadcrumbs}
|
||||
startIndex={startIndex}
|
||||
onBreadcrumbClick={onBreadcrumbClick}
|
||||
/>
|
||||
</PortalToFollowElemContent>
|
||||
<span className='system-xs-regular text-divider-deep'>/</span>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Dropdown)
|
||||
@ -0,0 +1,28 @@
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
type ItemProps = {
|
||||
name: string
|
||||
index: number
|
||||
onBreadcrumbClick: (index: number) => void
|
||||
}
|
||||
|
||||
const Item = ({
|
||||
name,
|
||||
index,
|
||||
onBreadcrumbClick,
|
||||
}: ItemProps) => {
|
||||
const handleClick = useCallback(() => {
|
||||
onBreadcrumbClick(index)
|
||||
}, [index, onBreadcrumbClick])
|
||||
|
||||
return (
|
||||
<div
|
||||
className='system-md-regular rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover'
|
||||
onClick={handleClick}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Item)
|
||||
@ -0,0 +1,30 @@
|
||||
import React from 'react'
|
||||
import Item from './item'
|
||||
|
||||
type MenuProps = {
|
||||
breadcrumbs: string[]
|
||||
startIndex: number
|
||||
onBreadcrumbClick: (index: number) => void
|
||||
}
|
||||
|
||||
const Menu = ({
|
||||
breadcrumbs,
|
||||
startIndex,
|
||||
onBreadcrumbClick,
|
||||
}: MenuProps) => {
|
||||
return (
|
||||
<div className='flex w-[136px] flex-col rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg shadow-shadow-shadow-5 backdrop-blur-[5px]'>
|
||||
{breadcrumbs.map((breadcrumb, index) => {
|
||||
return (
|
||||
<Item
|
||||
name={breadcrumb}
|
||||
index={startIndex + index}
|
||||
onBreadcrumbClick={onBreadcrumbClick}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Menu)
|
||||
Loading…
Reference in New Issue