import { FileItem } from '@/lib/api' import { X } from 'lucide-react' import { clsx } from 'clsx' import { useWallpaper } from '@/stores' import { useEffect, useRef, useState } from 'react' import { ContextMenu } from '@/components/common/ContextMenu' import { getModuleTabId } from '@/lib/module-registry' const HOME_TAB_ID = getModuleTabId('home') ?? 'home-tab' export interface TabBarProps { openFiles: FileItem[] activeFile: FileItem | null onTabClick: (file: FileItem) => void onTabClose: (file: FileItem, e: React.MouseEvent) => void onCloseOther?: (file: FileItem) => void onCloseAll?: () => void onPopOut?: (file: FileItem) => void className?: string style?: React.CSSProperties variant?: 'default' | 'titlebar' } export const TabBar = ({ openFiles, activeFile, onTabClick, onTabClose, onCloseOther, onCloseAll, onPopOut, className, style, variant = 'default' }: TabBarProps) => { const scrollContainerRef = useRef(null) const { opacity } = useWallpaper() const [contextMenu, setContextMenu] = useState<{ isOpen: boolean position: { x: number; y: number } file: FileItem | null }>({ isOpen: false, position: { x: 0, y: 0 }, file: null }) const handleContextMenu = (e: React.MouseEvent, file: FileItem) => { e.preventDefault() e.stopPropagation() setContextMenu({ isOpen: true, position: { x: e.clientX, y: e.clientY }, file }) } const handleCloseContextMenu = () => { setContextMenu(prev => ({ ...prev, isOpen: false })) } const handleCloseOther = () => { if (contextMenu.file && onCloseOther) { onCloseOther(contextMenu.file) } handleCloseContextMenu() } const handleCloseAll = () => { if (onCloseAll) { onCloseAll() } handleCloseContextMenu() } const handlePopOut = () => { if (contextMenu.file && onPopOut) { onPopOut(contextMenu.file) } handleCloseContextMenu() } const isHomeTab = contextMenu.file?.path === HOME_TAB_ID const contextMenuItems = [ ...(!isHomeTab ? [{ label: '在新窗口中打开', onClick: handlePopOut }] : []), { label: '关闭其他标签页', onClick: handleCloseOther }, { label: '关闭所有标签页', onClick: handleCloseAll } ] useEffect(() => { if (activeFile && scrollContainerRef.current) { const activeTab = scrollContainerRef.current.querySelector('[data-active="true"]') if (activeTab) { activeTab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' }) } } }, [activeFile?.path, openFiles.length]) if (openFiles.length === 0) return null const isTitlebar = variant === 'titlebar' return (
{openFiles.map((file) => { const isActive = activeFile?.path === file.path const isOnlyHomeTab = openFiles.length === 1 && file.path === HOME_TAB_ID return (
onTabClick(file)} onContextMenu={(e) => handleContextMenu(e, file)} className={clsx( "group relative flex items-center px-3 min-w-[80px] max-w-[240px] text-sm cursor-pointer border-r border-gray-200 dark:border-gray-700/60 select-none rounded-t-md flex-1 titlebar-no-drag", isTitlebar ? "h-full" : "h-10", isActive ? "backdrop-blur-md text-gray-800 dark:text-gray-200 font-medium border-t-2 border-t-gray-400 dark:border-t-gray-500" : "text-gray-600 dark:text-gray-300 hover:bg-gray-100/[var(--tab-opacity)] dark:hover:bg-gray-700/[var(--tab-opacity)] border-t-2 border-t-transparent" )} style={{ backgroundColor: isActive ? `rgba(var(--app-tab-active-bg-rgb), ${opacity * 0.55})` : `rgba(var(--app-tab-inactive-bg-rgb), ${opacity * 0.65})`, }} > {file.name} {!isOnlyHomeTab && ( )}
) })}
) }