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