dify/web/app/components/integrations/sidebar-nav-item.tsx
Jingyi 9b74df21d0
feat(web): refine onboarding UI (#37433)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: hjlarry <hjlarry@163.com>
Co-authored-by: fatelei <fatelei@gmail.com>
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com>
Co-authored-by: gigglewang <gigglewang@dify.ai>
Co-authored-by: Yunlu Wen <yunlu.wen@dify.ai>
Co-authored-by: chariri <w@chariri.moe>
Co-authored-by: Evan <2869018789@qq.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
2026-06-15 08:47:15 +00:00

108 lines
2.8 KiB
TypeScript

'use client'
import type { ComponentType } from 'react'
import type { IntegrationSection } from '@/app/components/integrations/routes'
import { cn } from '@langgenius/dify-ui/cn'
import Link from '@/next/link'
import { buildIntegrationPath } from './routes'
import {
integrationSidebarActiveNavItemClassName,
integrationSidebarDisabledNavItemClassName,
integrationSidebarInactiveNavItemClassName,
integrationSidebarNavItemClassName,
} from './sidebar-nav-item-styles'
type IconComponent = ComponentType<{ className?: string }>
export type IntegrationSidebarNavItemData = {
activeIcon?: IconComponent | string
className?: string
disabled?: boolean
icon: IconComponent | string
iconClassName?: string
label: string
section?: IntegrationSection
}
const renderIcon = (icon: IconComponent | string, className = 'size-4') => {
if (typeof icon === 'string')
return <span className={cn(className, icon)} />
const Icon = icon
return <Icon className={className} />
}
type IntegrationSidebarNavItemProps = {
item: IntegrationSidebarNavItemData
onSelect?: (section: IntegrationSection) => void
section: IntegrationSection
}
export function IntegrationSidebarNavItem({
item,
onSelect,
section,
}: IntegrationSidebarNavItemProps) {
const isActive = item.section === section
const icon = isActive && item.activeIcon ? item.activeIcon : item.icon
const className = cn(
integrationSidebarNavItemClassName,
isActive ? integrationSidebarActiveNavItemClassName : integrationSidebarInactiveNavItemClassName,
item.className,
)
if (!item.section) {
return (
<div
aria-label={item.label}
className={cn(
integrationSidebarNavItemClassName,
integrationSidebarDisabledNavItemClassName,
item.className,
)}
aria-disabled="true"
>
<span aria-hidden className="flex size-5 shrink-0 items-center justify-center">
{renderIcon(item.icon, item.iconClassName)}
</span>
<span className="min-w-0 truncate" title={item.label}>{item.label}</span>
</div>
)
}
const content = (
<>
<span aria-hidden className="flex size-5 shrink-0 items-center justify-center">
{renderIcon(icon, item.iconClassName)}
</span>
<span className="min-w-0 truncate" title={item.label}>{item.label}</span>
</>
)
if (onSelect) {
return (
<button
type="button"
aria-label={item.label}
aria-pressed={isActive}
className={cn('border-none bg-transparent', className)}
onClick={() => onSelect(item.section!)}
>
{content}
</button>
)
}
return (
<Link
href={buildIntegrationPath(item.section)}
aria-label={item.label}
aria-current={isActive ? 'page' : undefined}
className={className}
>
{content}
</Link>
)
}