diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 8017ff63c..7ea1cc2ab 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -5634,6 +5634,21 @@ iframe.preview-frame { pointer-events: none; } +.game-resource-book-loading { + position: absolute; + inset: 0; + z-index: 40; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; + background: rgb(255 253 250 / 78%); + color: #a08073; + font-size: 13px; + pointer-events: none; +} + .game-resource-book-manager[data-book-motion='running'] .game-resource-book-scene-world { opacity: 0; 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 ed658b681..d24b0fc2b 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 @@ -10,6 +10,7 @@ import { Image, Info, ListFilter, + Loader2, Maximize2, Minus, Music2, @@ -98,6 +99,7 @@ import { } from './resourceBookLayout'; import { initialResourceBookState, + resourceBookIsLoading, resourceBookReducer, resourceBookSceneCategory, resourceBookShowsChildCards, @@ -2189,6 +2191,36 @@ export default function ProjectDevelopmentView({ sortMode, visibleCategoryOrder, ]); + const resourceBookOverviewReady = useMemo( + () => + visibleCategoryOrder.every((category) => { + const rect = resourceBookOverviewRects.get(category); + return Boolean(rect && rect.width > 0 && rect.height > 0); + }), + [resourceBookOverviewRects, visibleCategoryOrder], + ); + const resourceBookSettledPreviewCount = useMemo(() => { + let settled = 0; + for (const resource of visibleResources) { + const identity = resourceCardPreviews.identityByResourceId.get( + resource.id, + ); + if (!identity) continue; + const status = resourceCardPreviews.previews.get(identity)?.status; + if (status === 'loaded' || status === 'failed') settled += 1; + } + return settled; + }, [ + resourceCardPreviews.identityByResourceId, + resourceCardPreviews.previews, + visibleResources, + ]); + const resourceBookLoading = resourceBookIsLoading({ + resourceCount: visibleResources.length, + overviewReady: resourceBookOverviewReady, + cardsReady: sortMode !== 'dependency' || resourceGraphInitializationReady, + settledPreviewCount: resourceBookSettledPreviewCount, + }); const setResourceCanvasViewport = useCallback( ( category: ResourceCategory, @@ -5590,6 +5622,20 @@ export default function ProjectDevelopmentView({ onWheel={handleResourceBookWheel} /> + {resourceBookLoading ? ( +
+
+ ) : null}