修复资源画布溢出与模板资源投影
闭合资源画布横向收缩链并增加内部滚动条 过滤任务产物通配模板避免生成无效资源卡 补充布局与资源投影回归测试 同步工作台文档与共享排障记忆
This commit is contained in:
@@ -3736,6 +3736,7 @@ iframe.preview-frame {
|
||||
.game-workbench-stage {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: auto auto minmax(0, 1fr);
|
||||
}
|
||||
|
||||
@@ -3840,7 +3841,9 @@ iframe.preview-frame {
|
||||
.game-resource-manager {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.game-resource-search {
|
||||
@@ -3894,14 +3897,43 @@ iframe.preview-frame {
|
||||
.game-resource-canvas {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
overflow: auto;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
scrollbar-color: #d5a089 #f7e7df;
|
||||
scrollbar-width: thin;
|
||||
background-color: #fffdfa;
|
||||
background-image: radial-gradient(#eaded8 0.8px, transparent 0.8px);
|
||||
background-size: 18px 18px;
|
||||
}
|
||||
|
||||
.game-resource-canvas::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.game-resource-canvas::-webkit-scrollbar-track {
|
||||
border-radius: 999px;
|
||||
background: #f7e7df;
|
||||
}
|
||||
|
||||
.game-resource-canvas::-webkit-scrollbar-thumb {
|
||||
border: 2px solid #f7e7df;
|
||||
border-radius: 999px;
|
||||
background: #d5a089;
|
||||
}
|
||||
|
||||
.game-resource-canvas::-webkit-scrollbar-thumb:hover {
|
||||
background: #c98566;
|
||||
}
|
||||
|
||||
.game-resource-canvas::-webkit-scrollbar-corner {
|
||||
background: #f7e7df;
|
||||
}
|
||||
|
||||
.game-resource-canvas-content {
|
||||
position: relative;
|
||||
display: grid;
|
||||
|
||||
@@ -58,6 +58,11 @@ function fileName(path: string) {
|
||||
return path.split(/[\\/]/u).filter(Boolean).pop() || path;
|
||||
}
|
||||
|
||||
function isConcreteTaskArtifactPath(path: string) {
|
||||
const normalizedPath = path.trim();
|
||||
return normalizedPath.length > 0 && !/[*?\[\]{}]/u.test(normalizedPath);
|
||||
}
|
||||
|
||||
export function classifyProjectedResource(input: {
|
||||
path: string;
|
||||
mediaType: string;
|
||||
@@ -119,6 +124,9 @@ export function projectResourcesFromReadModels(
|
||||
continue;
|
||||
}
|
||||
for (const path of task.artifacts) {
|
||||
if (!isConcreteTaskArtifactPath(path)) {
|
||||
continue;
|
||||
}
|
||||
const category = classifyProjectedResource({ path, mediaType: '' });
|
||||
if (!category || category === 'audio') {
|
||||
continue;
|
||||
|
||||
@@ -56,6 +56,10 @@ describe('项目资源投影', () => {
|
||||
'memory/game-design.md',
|
||||
'assets/ui-preview.svg',
|
||||
'build/game.bundle',
|
||||
'.agent/passes/pass-*/groups/design/director.md',
|
||||
'memory/draft?.md',
|
||||
'assets/[ab].png',
|
||||
'memory/{draft,final}.md',
|
||||
];
|
||||
audioTask.status = 'completed';
|
||||
audioTask.artifacts = ['audio/unregistered-bgm.wav'];
|
||||
@@ -151,6 +155,10 @@ describe('项目资源投影', () => {
|
||||
[
|
||||
'task:design-foundation:build/game.bundle',
|
||||
'task:audio-asset-plan:audio/unregistered-bgm.wav',
|
||||
'task:design-foundation:.agent/passes/pass-*/groups/design/director.md',
|
||||
'task:design-foundation:memory/draft?.md',
|
||||
'task:design-foundation:assets/[ab].png',
|
||||
'task:design-foundation:memory/{draft,final}.md',
|
||||
'asset:unknown-binary',
|
||||
'attachment:imports/archive.zip',
|
||||
].includes(id),
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
@@ -6,6 +9,38 @@ import {
|
||||
} from '../../../packages/shared/src/contracts/gameCreationApp';
|
||||
|
||||
describe('resource canvas layout contract', () => {
|
||||
it('keeps wide resource content inside an explicitly scrollable stage column', () => {
|
||||
const styles = readFileSync(
|
||||
resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'),
|
||||
'utf8',
|
||||
);
|
||||
const stageRule = styles.match(
|
||||
/\.game-workbench-stage\s*\{([^}]*)\}/s,
|
||||
);
|
||||
const managerRule = styles.match(
|
||||
/\.game-resource-manager\s*\{([^}]*)\}/s,
|
||||
);
|
||||
const canvasRule = styles.match(
|
||||
/\.game-resource-canvas\s*\{([^}]*)\}/s,
|
||||
);
|
||||
|
||||
expect(stageRule?.[1]).toContain(
|
||||
'grid-template-columns: minmax(0, 1fr);',
|
||||
);
|
||||
expect(managerRule?.[1]).toContain('min-width: 0;');
|
||||
expect(managerRule?.[1]).toContain('overflow: hidden;');
|
||||
expect(canvasRule?.[1]).toContain('width: 100%;');
|
||||
expect(canvasRule?.[1]).toContain('min-width: 0;');
|
||||
expect(canvasRule?.[1]).toContain('overflow-x: auto;');
|
||||
expect(canvasRule?.[1]).toContain('overflow-y: auto;');
|
||||
expect(styles).toMatch(
|
||||
/\.game-resource-canvas::-webkit-scrollbar\s*\{[^}]*height:\s*12px/s,
|
||||
);
|
||||
expect(styles).toMatch(
|
||||
/\.game-resource-canvas::-webkit-scrollbar-thumb\s*\{[^}]*background:\s*#d5a089/s,
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps revisions inside the JSON safe integer range', () => {
|
||||
const maxRevision = GAME_CREATION_RESOURCE_LAYOUT_MAX_SAFE_REVISION;
|
||||
expect(JSON.parse(JSON.stringify({ revision: maxRevision }))).toEqual({
|
||||
|
||||
Reference in New Issue
Block a user