082d8d62de
- 新增「信息」动作:排在「@引用」之后、「编辑标签」之前,点开非模态信息浮层,再点一次即收起(aria-pressed 反映开合) - 新增只读字段组件 ResourceInfoFieldsView(ResourceInfoPanelView.tsx),运行页签的「信息展示」与画布浮层共用,字段清单只在 resolveResourceInfoFieldRows 单点定义 - 字段口径:名称 / 路径 / 类型 + 只读分类与标签(分类取画布栏目口径,标签为空时给「暂无标签」),刻意不含来源任务、资产 ID 等 manifest 内部标识 - 浮层 chrome 与快速编辑浮层同族(同一锚点、同档圆角与阴影),样式落在 resourceCanvasChrome.css;关闭入口三处:动作按钮、面板关闭按钮、画布浮层统一的 Esc / 点边界外 - 关闭判据收口:resolveResourceCanvasQuickEditDismissOpen 更名为 resolveResourceCanvasFloatingPanelDismissOpen、参数改为 isFloatingPanelOpen,宿主把「快速编辑开」与「信息开」合成一个布尔 - .game-resource-info-panel 补进 RESOURCE_CANVAS_INTERACTION_SELECTOR,否则点在只读字段值上会被判成点画布空白而清掉选中 - 换选 / 清空选中 / 切项目时信息浮层自动收起:在选中派生处按 selectedResourceId 收口,不在每个重置点各补一行 - 测试:新增 resourceCanvasInfoModel 三条与「信息面板在画布浮层与运行页签里渲染同一份只读字段」(工具条顺序、开合、关闭按钮只收面板、点画布以外收起、Esc 连工具条一起收、运行页签字段逐行相同);resourceCanvasFloatingDismiss 的判据用例与交互选择器夹具改为浮层通用口径 - resourceCanvasChrome.css 的字段排版收在浮层选择器下,不跨上下文改运行页签的字号与列宽 - decision-log 新增一条:记录这次对 Issue #309 C3「取消资源详情面板」的有意局部回退(只回退「看信息」,不恢复可编辑详情面板与全屏编辑路由),并登记需要同步的 C3 引用位置
97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import { describe, expect, test } from 'vitest';
|
|
|
|
import {
|
|
resolveResourceInfoFieldRows,
|
|
resolveResourceInfoPanelStyle,
|
|
} from '../src/features/resource-canvas/resourceCanvasInfoModel';
|
|
import type { ProjectResource } from '../src/view/project-development/resourceProjectionModel';
|
|
|
|
function resourceFixture(overrides: Partial<ProjectResource>): ProjectResource {
|
|
return {
|
|
id: 'asset:hero',
|
|
category: 'character',
|
|
subtype: 'character',
|
|
label: 'hero.png',
|
|
path: 'assets/hero.png',
|
|
mediaType: 'image/png',
|
|
sourceLabel: 'Agent 生成',
|
|
taskTitle: null,
|
|
manifestAssetId: 'hero',
|
|
producerTaskId: null,
|
|
externalResourceId: null,
|
|
referenceResourceIds: [],
|
|
dependencies: [],
|
|
dependencyDepth: 0,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
const SOURCE_LAYER = {
|
|
id: 'asset:hero',
|
|
resourceId: 'asset:hero',
|
|
title: 'hero.png',
|
|
src: 'blob:hero',
|
|
x: 100,
|
|
y: 40,
|
|
width: 200,
|
|
height: 120,
|
|
originalWidth: 200,
|
|
originalHeight: 120,
|
|
zIndex: 1,
|
|
sourceType: 'generated' as const,
|
|
};
|
|
|
|
describe('resourceCanvasInfoModel', () => {
|
|
test('字段固定为名称 / 路径 / 类型 + 只读分类与标签', () => {
|
|
expect(resolveResourceInfoFieldRows(resourceFixture({}))).toEqual([
|
|
{ label: '名称', value: 'hero.png' },
|
|
{ label: '路径', value: 'assets/hero.png' },
|
|
{ label: '类型', value: 'image/png' },
|
|
{ label: '分类', value: '角色与对象' },
|
|
{ label: '标签', value: '暂无标签' },
|
|
]);
|
|
|
|
// 面板是给用户看的事实卡:manifest 内部标识(来源任务、资产 ID、producer)不上桌。
|
|
const labels = resolveResourceInfoFieldRows(resourceFixture({})).map(
|
|
(row) => row.label,
|
|
);
|
|
for (const forbidden of ['来源任务', '资产 ID', 'ID', '来源']) {
|
|
expect(labels).not.toContain(forbidden);
|
|
}
|
|
});
|
|
|
|
test('分类跟随画布栏目口径,标签只读拼接', () => {
|
|
expect(
|
|
resolveResourceInfoFieldRows(
|
|
resourceFixture({ category: 'version', assetCategory: undefined }),
|
|
).find((row) => row.label === '分类')?.value,
|
|
).toBe('项目版本');
|
|
expect(
|
|
resolveResourceInfoFieldRows(
|
|
resourceFixture({ category: 'unclassified', assetCategory: undefined }),
|
|
).find((row) => row.label === '分类')?.value,
|
|
).toBe('待归类');
|
|
expect(
|
|
resolveResourceInfoFieldRows(
|
|
resourceFixture({ assetTags: ['主角', '待定稿'] }),
|
|
).find((row) => row.label === '标签')?.value,
|
|
).toBe('主角、待定稿');
|
|
});
|
|
|
|
test('浮层锚点与快速编辑浮层同一条几何:没有选中图层就没有面板', () => {
|
|
const anchor = {
|
|
sourceLayer: SOURCE_LAYER,
|
|
viewport: { scale: 1, x: 0, y: 0 },
|
|
canvasSize: { width: 900, height: 600 },
|
|
};
|
|
// 锚在图层下沿居中 + 12px 间距(与 `resolveQuickEditPanelStyle` 同口径)。
|
|
expect(resolveResourceInfoPanelStyle(anchor)).toEqual({
|
|
left: 200,
|
|
top: 172,
|
|
});
|
|
expect(
|
|
resolveResourceInfoPanelStyle({ ...anchor, sourceLayer: null }),
|
|
).toBeNull();
|
|
});
|
|
});
|