dify/web/app/components/workflow/skill/editor-tab-item.tsx
2026-01-15 16:45:40 +08:00

84 lines
2.4 KiB
TypeScript

'use client'
import type { FC } from 'react'
import type { FileAppearanceType } from '@/app/components/base/file-uploader/types'
import { RiCloseLine } from '@remixicon/react'
import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import FileTypeIcon from '@/app/components/base/file-uploader/file-type-icon'
import { cn } from '@/utils/classnames'
import { getFileIconType } from './utils/file-utils'
type EditorTabItemProps = {
fileId: string
name: string
isActive: boolean
isDirty: boolean
onClick: (fileId: string) => void
onClose: (fileId: string) => void
}
const EditorTabItem: FC<EditorTabItemProps> = ({
fileId,
name,
isActive,
isDirty,
onClick,
onClose,
}) => {
const { t } = useTranslation()
const iconType = getFileIconType(name)
const handleClick = useCallback(() => {
onClick(fileId)
}, [onClick, fileId])
const handleClose = useCallback((e: React.MouseEvent) => {
e.stopPropagation()
onClose(fileId)
}, [onClose, fileId])
return (
<div
className={cn(
'group relative flex shrink-0 cursor-pointer items-center gap-1.5 border-r border-components-panel-border-subtle px-2.5 pb-2 pt-2.5',
isActive ? 'bg-components-panel-bg' : 'bg-transparent hover:bg-state-base-hover',
)}
onClick={handleClick}
>
<div className="relative flex size-5 shrink-0 items-center justify-center">
<FileTypeIcon type={iconType as FileAppearanceType} size="sm" />
{isDirty && (
<span className="absolute -bottom-px -right-px size-[7px] rounded-full border border-white bg-text-warning-secondary" />
)}
</div>
<span
className={cn(
'max-w-40 truncate text-[13px] font-normal leading-4',
isActive
? 'text-text-primary'
: 'text-text-tertiary',
)}
>
{name}
</span>
<button
type="button"
className={cn(
'ml-0.5 flex size-4 items-center justify-center rounded-[6px] text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
isActive ? 'opacity-100' : 'opacity-0 group-hover:opacity-100',
)}
aria-label={t('operation.close', { ns: 'common' })}
onClick={handleClose}
>
<RiCloseLine className="size-4" />
</button>
</div>
)
}
export default React.memo(EditorTabItem)