Files
esengine/packages/editor-app/src/components/SceneHierarchy.tsx

77 lines
2.5 KiB
TypeScript
Raw Normal View History

2025-10-14 23:31:09 +08:00
import { useState, useEffect } from 'react';
import { Entity } from '@esengine/ecs-framework';
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
2025-10-14 23:56:54 +08:00
import { useLocale } from '../hooks/useLocale';
2025-10-15 17:15:05 +08:00
import { Box, Layers } from 'lucide-react';
2025-10-14 23:31:09 +08:00
import '../styles/SceneHierarchy.css';
interface SceneHierarchyProps {
entityStore: EntityStoreService;
messageHub: MessageHub;
}
export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps) {
const [entities, setEntities] = useState<Entity[]>([]);
const [selectedId, setSelectedId] = useState<number | null>(null);
2025-10-14 23:56:54 +08:00
const { t } = useLocale();
2025-10-14 23:31:09 +08:00
useEffect(() => {
const updateEntities = () => {
setEntities(entityStore.getRootEntities());
};
const handleSelection = (data: { entity: Entity | null }) => {
setSelectedId(data.entity?.id ?? null);
};
updateEntities();
const unsubAdd = messageHub.subscribe('entity:added', updateEntities);
const unsubRemove = messageHub.subscribe('entity:removed', updateEntities);
const unsubClear = messageHub.subscribe('entities:cleared', updateEntities);
const unsubSelect = messageHub.subscribe('entity:selected', handleSelection);
return () => {
unsubAdd();
unsubRemove();
unsubClear();
unsubSelect();
};
}, [entityStore, messageHub]);
const handleEntityClick = (entity: Entity) => {
entityStore.selectEntity(entity);
};
return (
<div className="scene-hierarchy">
<div className="hierarchy-header">
2025-10-15 17:15:05 +08:00
<Layers size={16} className="hierarchy-header-icon" />
2025-10-14 23:56:54 +08:00
<h3>{t('hierarchy.title')}</h3>
2025-10-14 23:31:09 +08:00
</div>
2025-10-15 17:15:05 +08:00
<div className="hierarchy-content scrollable">
2025-10-14 23:31:09 +08:00
{entities.length === 0 ? (
2025-10-15 17:15:05 +08:00
<div className="empty-state">
<Box size={48} strokeWidth={1.5} className="empty-icon" />
<div className="empty-title">{t('hierarchy.empty')}</div>
<div className="empty-hint">Create an entity to get started</div>
</div>
2025-10-14 23:31:09 +08:00
) : (
<ul className="entity-list">
{entities.map(entity => (
<li
key={entity.id}
className={`entity-item ${selectedId === entity.id ? 'selected' : ''}`}
onClick={() => handleEntityClick(entity)}
>
2025-10-15 17:15:05 +08:00
<Box size={14} className="entity-icon" />
2025-10-14 23:31:09 +08:00
<span className="entity-name">Entity {entity.id}</span>
</li>
))}
</ul>
)}
</div>
</div>
);
}