Files
Genarrative/apps/ai-game-creator-shell/src/view/project-development/ResourceInfoPanelView.tsx
T
suzmii 7ce4a3a9c6 把素材类型从「编辑素材标签」面板拆成独立入口
- 新增 ResourceTypePanel(src/view/project-development/ResourceTypePanel.tsx):类型选一项即落盘,category 传用户选中值、tags 逐字回传落盘原值,保存在飞时沿用 closeOnBackdrop/closeOnEscape = !saving
- 新增 resourceAssetDisplayName.ts:两块面板共用同一个素材名副标题口径(localPath basename),不再各写一份
- 新增 resourceTypePanel.css:类型面板的弹窗骨架与信息浮层「分类」行入口样式,按 AGC 内独立文件约定,不动 packages/** 与 styles.css
- ResourceClassificationPanel 删掉类型 chip 与 categoryChoice:保存时恒回传 gameCreationAppAssetPersistedCategory(asset),「只改标签不动分类」由结构保证
- index.tsx 新增 resourceTypeAssetId 与 resourceTypeAsset;工具条在「编辑标签」旁新增「素材类型」按钮(Shapes 图标)
- index.tsx 用合并后的 resourceClassificationOverlayOpen 纳入点外部/Esc 浮层遮挡判据,并同步 useEffect 依赖项
- index.tsx 渲染新面板:保存成功后由宿主收起面板并沿用 manifest 重载路径,让卡片立刻落到新栏目
- 信息浮层「分类」行接出第二入口:按钮渲染在 dd 之外,不污染 dt/dd 字段读取口径;非 manifest 资产不给入口
- resourceCanvasInfoModel 导出 RESOURCE_INFO_CATEGORY_FIELD_LABEL,模型与入口共用同一行标识
- 新增 tests/resourceTypePanel.test.tsx:选中即落盘、tags 逐字回传、没碰过不写盘、显式待归类、失败回退、saving 锁、Esc/遮罩、面板骨架共 11 条
- 迁移「没碰过分类就回传落盘原值」对照用例并保留两条(标签面板侧),chip 用例搬到新面板文件
- 集成用例改走新入口:选中即落盘并自动关窗,另补 Esc/点外部不串台、只改标签后 manifest category 逐字不变两条宿主级用例
- appSurface 工具条清单补上「素材类型」
2026-09-14 17:07:15 +08:00

109 lines
3.1 KiB
TypeScript

import { Info, X } from 'lucide-react';
import {
resolveResourceInfoFieldRows,
resolveResourceInfoPanelStyle,
RESOURCE_INFO_CATEGORY_FIELD_LABEL,
type ResourceInfoPanelAnchor,
} from '../../features/resource-canvas/resourceCanvasInfoModel';
import type { ProjectResource } from './resourceProjectionModel';
/**
* 只读资源信息字段。运行页签的「信息展示」与画布上的信息浮层共用这一份,
* 字段清单只在 `resolveResourceInfoFieldRows` 里定义,两处不会各说一套。
*
* `onEditCategory` 是「分类」行的可选入口(只有画布浮层传):分类值本身仍然只读展示,
* 入口按钮渲染在 `dd` **外面** —— 字段值的读取口径是 `dt` / `dd` 的文本,
* 把按钮塞进 `dd` 会让分类值变成「角色与对象设置」这类拼接文案。
*/
export function ResourceInfoFieldsView({
resource,
onEditCategory,
}: {
resource: ProjectResource;
onEditCategory?: () => void;
}) {
return (
<dl className="game-resource-info-fields">
{resolveResourceInfoFieldRows(resource).map((row) => (
<div key={row.label}>
<dt>{row.label}</dt>
<dd>{row.value}</dd>
{onEditCategory &&
row.label === RESOURCE_INFO_CATEGORY_FIELD_LABEL ? (
<button
type="button"
className="game-resource-info-field-action"
aria-label="设置素材类型"
title="设置素材类型"
onClick={onEditCategory}
>
设置
</button>
) : null}
</div>
))}
</dl>
);
}
export type ResourceInfoPanelViewProps = ResourceInfoPanelAnchor & {
resource: ProjectResource;
/**
* 「分类」行的类型设置入口;不传就没有入口(资源不是 manifest 资产时宿主不传)。
*/
onEditCategory?: () => void;
onClose: () => void;
};
/**
* 画布上的信息浮层:贴着选中资源卡,非模态。
*
* 关闭时机(Esc / 点边界外)由宿主复用 `useImageCanvasFloatingOptionDismiss` 接管,
* 这里只负责渲染,所以面板本身不注册任何 document 监听。
*/
export function ResourceInfoPanelView({
resource,
sourceLayer,
viewport,
canvasSize,
onEditCategory,
onClose,
}: ResourceInfoPanelViewProps) {
const style = resolveResourceInfoPanelStyle({
sourceLayer,
viewport,
canvasSize,
});
if (!style) {
return null;
}
return (
<section
className="game-resource-info-panel"
role="dialog"
aria-label="资源信息"
style={style}
>
<header className="game-resource-info-panel__header">
<Info size={14} aria-hidden="true" />
<strong>信息</strong>
<button
type="button"
className="game-resource-info-panel__close"
aria-label="关闭信息面板"
title="关闭"
onClick={onClose}
>
<X size={14} aria-hidden="true" />
</button>
</header>
<ResourceInfoFieldsView
resource={resource}
onEditCategory={onEditCategory}
/>
</section>
);
}