diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 8bc7b0bf7..18b025651 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -6650,6 +6650,65 @@ iframe.preview-frame { font-size: 12px; } +/* + * 「所有资源」页。 + * + * 资源总览第 0 张卡打开的汇总页:左侧沿用栏目大纲,正文按栏目分组的滚动卡片网格。 + * 整页自成一层(`z-index: 21`):栏目态的画本场景自带一层不透明底纹(`z-index: 20`), + * 只在 `z-index: auto` 上铺会被它盖住;同时它不落在 `.game-resource-canvas` 里, + * 那层挂着画布平移/框选的指针与滚轮处理器,会把这里的滚动吃掉。 + * + * 卡片本体仍由栏目页同一颗卡片渲染器产出(尺寸取画布默认卡宽高), + * 因此这一页只补齐容器与网格,不新增卡片样式。 + */ +.game-resource-all-resources-host { + position: absolute; + z-index: 21; + inset: 0; + padding: 12px; + overflow: hidden; + background-color: #fffdfa; + background-image: radial-gradient(#eaded8 0.8px, transparent 0.8px); + background-size: 18px 18px; +} + +.game-resource-all-scroll { + display: grid; + gap: 14px; + align-content: start; + min-height: 0; + padding: 2px; + overflow: auto; + overscroll-behavior: contain; +} + +.game-resource-all-section { + display: grid; + gap: 10px; + padding: 12px; + border: 1px solid #ecdfd8; + border-radius: 12px; + background: rgb(255 253 250 / 82%); +} + +.game-resource-all-grid { + display: grid; + grid-template-columns: repeat(auto-fill, 180px); + gap: 14px; +} + +.game-resource-all-card { + position: relative; + display: block; +} + +/* 只浏览的页面不接拖拽:光标如实反映「点选 / 播放」,并且把纵向触摸手势交还给滚动容器 + (`.game-resource-card` 常态是 `touch-action: none`,那是画布拖卡需要的)。 */ +.game-resource-all-grid .game-resource-card { + cursor: pointer; + touch-action: pan-y; +} + .game-resource-section-stack { display: contents; } diff --git a/apps/ai-game-creator-shell/src/view/project-development/index.tsx b/apps/ai-game-creator-shell/src/view/project-development/index.tsx index d5c7766a5..e5ea3cdca 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/index.tsx +++ b/apps/ai-game-creator-shell/src/view/project-development/index.tsx @@ -22,6 +22,7 @@ import { Gamepad2, Image, Info, + Layers, LayoutGrid, ListFilter, Maximize2, @@ -149,7 +150,10 @@ import { type ResourceBookTransitionController, } from './resourceBookController'; import { + buildResourceBookAllResourcesSections, buildResourceBookScenePlan, + RESOURCE_BOOK_OVERVIEW_STACK_LIMIT, + type ResourceBookAllResourcesSection, type ResourceBookOverviewRect, resourceBookSceneCardKey, resourceBookSceneCardLayoutSignature, @@ -159,8 +163,12 @@ import { } from './resourceBookLayout'; import { initialResourceBookState, + isResourceBookAllTarget, + RESOURCE_BOOK_ALL_TARGET, + type ResourceBookCategory, resourceBookReducer, type ResourceBookState, + type ResourceBookTarget, } from './resourceBookModel'; import { DEFAULT_RESOURCE_BOOK_VIEWPORT, @@ -456,8 +464,11 @@ const categoryOrder = RESOURCE_CANVAS_SECTION_ORDER; /** * 栏目标签复用资源筛选的唯一中文口径;「项目版本」不是资源资产、单独成栏, * 不在筛选口径内,因此只有它在这里给出文案。 + * + * `all` 是渲染层的「所有资源」入口(见 `RESOURCE_BOOK_ALL_TARGET`),不是真实栏目, + * 因此只在这里补文案与图标,不进入跨端契约的分区枚举。 */ -const categoryLabels: Record = { +const categoryLabels: Record = { 'ui-interaction': resourceReferenceCategoryLabel('ui-interaction'), character: resourceReferenceCategoryLabel('character'), scene: resourceReferenceCategoryLabel('scene'), @@ -465,9 +476,10 @@ const categoryLabels: Record = { document: resourceReferenceCategoryLabel('document'), unclassified: resourceReferenceCategoryLabel('unclassified'), version: '项目版本', + [RESOURCE_BOOK_ALL_TARGET]: '所有资源', }; -const categoryIcons: Record = { +const categoryIcons: Record = { 'ui-interaction': LayoutGrid, character: Users, scene: Image, @@ -475,6 +487,7 @@ const categoryIcons: Record = { document: FileText, unclassified: PackageOpen, version: Gamepad2, + [RESOURCE_BOOK_ALL_TARGET]: Layers, }; const approvalOptions: Array<{ @@ -591,9 +604,10 @@ const ResourceCard = memo(function ResourceCard({ x: number, y: number, ) => void; - onPointerMove: (event: ReactPointerEvent) => void; - onPointerUp: (event: ReactPointerEvent) => void; - onPointerCancel: (event: ReactPointerEvent) => void; + /** 只浏览的页面(「所有资源」)不接拖拽,三个移动端回调可以整体缺省。 */ + onPointerMove?: (event: ReactPointerEvent) => void; + onPointerUp?: (event: ReactPointerEvent) => void; + onPointerCancel?: (event: ReactPointerEvent) => void; onObservePreview: ( element: HTMLElement, resource: ProjectResource, @@ -909,11 +923,11 @@ function ResourceBookThumbnail({ onOpen, registerElement, }: { - category: ResourceCategory; + category: ResourceBookTarget; resources: ProjectResource[]; - onOpen: (category: ResourceCategory) => void; + onOpen: (category: ResourceBookTarget) => void; registerElement?: ( - category: ResourceCategory, + category: ResourceBookTarget, element: HTMLElement | null, ) => void; }) { @@ -926,6 +940,11 @@ function ResourceBookThumbnail({ return groups; }, new Map()), ); + // 「所有资源」卡的正文只保留同一套占位摞结构:全量资源的张数由标题栏计数徽标表达, + // 卡片本体不进这一格(同一张资源卡已经在它所属栏目的摞里挂载过)。 + const bodyStacks = isResourceBookAllTarget(category) + ? stacks.slice(0, RESOURCE_BOOK_OVERVIEW_STACK_LIMIT) + : stacks; return (