({
projectPath,
locale = 'en',
onOpenScene,
isDrawer = false,
onDockInLayout,
revealPath
}: ContentBrowserProps)
| 222 | } |
| 223 | |
| 224 | export function ContentBrowser({ |
| 225 | projectPath, |
| 226 | locale = 'en', |
| 227 | onOpenScene, |
| 228 | isDrawer = false, |
| 229 | onDockInLayout, |
| 230 | revealPath |
| 231 | }: ContentBrowserProps) { |
| 232 | const { t } = useLocale(); |
| 233 | const messageHub = Core.services.resolve(MessageHub); |
| 234 | const fileActionRegistry = Core.services.resolve(FileActionRegistry); |
| 235 | |
| 236 | // Refs |
| 237 | const containerRef = useRef<HTMLDivElement>(null); |
| 238 | |
| 239 | // State |
| 240 | const [currentPath, setCurrentPath] = useState<string | null>(null); |
| 241 | const [selectedPaths, setSelectedPaths] = useState<Set<string>>(new Set()); |
| 242 | const [lastSelectedPath, setLastSelectedPath] = useState<string | null>(null); |
| 243 | const [assets, setAssets] = useState<AssetItem[]>([]); |
| 244 | const [searchQuery, setSearchQuery] = useState(''); |
| 245 | const [loading, setLoading] = useState(false); |
| 246 | const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid'); |
| 247 | |
| 248 | // 隐藏的文件扩展名(默认隐藏 .meta)| Hidden file extensions (hide .meta by default) |
| 249 | const [hiddenExtensions, setHiddenExtensions] = useState<Set<string>>(new Set(['meta'])); |
| 250 | const [showFilterDropdown, setShowFilterDropdown] = useState(false); |
| 251 | |
| 252 | // Folder tree state |
| 253 | const [folderTree, setFolderTree] = useState<FolderNode | null>(null); |
| 254 | const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set()); |
| 255 | |
| 256 | // Sections collapse state |
| 257 | const [favoritesExpanded, setFavoritesExpanded] = useState(true); |
| 258 | const [collectionsExpanded, setCollectionsExpanded] = useState(true); |
| 259 | |
| 260 | // Favorites (stored paths) |
| 261 | const [favorites] = useState<string[]>([]); |
| 262 | |
| 263 | // Dialog states |
| 264 | const [contextMenu, setContextMenu] = useState<{ |
| 265 | position: { x: number; y: number }; |
| 266 | asset: AssetItem | null; |
| 267 | isBackground?: boolean; |
| 268 | } | null>(null); |
| 269 | // Folder tree context menu (separate from asset context menu) |
| 270 | const [folderTreeContextMenu, setFolderTreeContextMenu] = useState<{ |
| 271 | position: { x: number; y: number }; |
| 272 | items: ContextMenuItem[]; |
| 273 | } | null>(null); |
| 274 | const [renameDialog, setRenameDialog] = useState<{ |
| 275 | asset: AssetItem; |
| 276 | newName: string; |
| 277 | } | null>(null); |
| 278 | const [deleteConfirmDialog, setDeleteConfirmDialog] = useState<AssetItem | null>(null); |
| 279 | const [createFileDialog, setCreateFileDialog] = useState<{ |
| 280 | parentPath: string; |
| 281 | template: FileCreationTemplate; |
nothing calls this directly
no test coverage detected