diff --git a/apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx b/apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx index 2f8007f69..67c08ccb5 100644 --- a/apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx +++ b/apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx @@ -72,7 +72,7 @@ const defaultRuntimeConfigDraft: GameCreatorAppConfig = { model: 'gpt-5.6-sol', apiKind: 'openai_responses', reasoningEffort: 'max', - stream: false, + stream: true, webSearchEnabled: false, contextWindowTokens: 128000, autoCompactTokenLimit: 64000, @@ -602,6 +602,18 @@ export function RuntimeConfigDialog({ useEscapeToClose(onClose); + useEffect(() => { + const htmlOverflow = document.documentElement.style.overflow; + const bodyOverflow = document.body.style.overflow; + document.documentElement.style.overflow = 'hidden'; + document.body.style.overflow = 'hidden'; + + return () => { + document.documentElement.style.overflow = htmlOverflow; + document.body.style.overflow = bodyOverflow; + }; + }, []); + useEffect(() => { void readRuntimeConfig(); // The dialog reads once on mount; subsequent reads are explicit user actions. diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index c6fe5d212..3db515b3f 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -3381,7 +3381,7 @@ h2 { padding: 11px 14px; border: 1px solid var(--platform-success-border); border-radius: 12px; - background: var(--platform-success-fill); + background: #edf8ef; box-shadow: var(--platform-panel-shadow); color: var(--platform-success-text); font-size: 12px; @@ -3391,7 +3391,7 @@ h2 { .runtime-settings-toast[data-tone='error'] { border-color: var(--platform-warm-border); - background: var(--platform-warm-bg); + background: #fff1ea; color: var(--platform-warm-text); } @@ -3411,6 +3411,11 @@ h2 { } .runtime-settings-panel { + --runtime-settings-fill: #fffdfa; + --runtime-settings-topbar-fill: #fffdf9; + --runtime-settings-nav-fill: #fdf7f1; + --runtime-settings-content-fill: #fffaf6; + --runtime-settings-subpanel-fill: #fffdfb; grid-template-rows: auto minmax(0, 1fr) auto; gap: 0; width: min(1080px, 100%); @@ -3420,7 +3425,7 @@ h2 { overflow: hidden; border-color: var(--platform-modal-border); border-radius: 18px; - background: var(--platform-modal-fill); + background: var(--runtime-settings-fill); box-shadow: var(--platform-panel-shadow); } @@ -3437,7 +3442,7 @@ h2 { min-height: 76px; padding: 15px 18px 14px 22px; border-bottom: 1px solid var(--platform-line-soft); - background: var(--platform-desktop-topbar-fill); + background: var(--runtime-settings-topbar-fill); } .runtime-settings-header > div { @@ -3488,7 +3493,7 @@ h2 { padding: 16px 12px; overflow-y: auto; border-right: 1px solid var(--platform-line-soft); - background: var(--platform-nav-fill); + background: var(--runtime-settings-nav-fill); } .runtime-settings-nav nav { @@ -3580,8 +3585,7 @@ h2 { min-height: 0; padding: 22px 24px 28px; overflow-y: auto; - background: var(--platform-desktop-panel-fill); - scrollbar-gutter: stable; + background: var(--runtime-settings-content-fill); } .runtime-settings-section-header { @@ -3618,7 +3622,7 @@ h2 { padding: 13px; border: 1px solid var(--platform-subpanel-border); border-radius: 12px; - background: var(--platform-subpanel-fill); + background: var(--runtime-settings-subpanel-fill); color: var(--platform-text-base); } @@ -3654,7 +3658,7 @@ h2 { overflow: hidden; border: 1px solid var(--platform-subpanel-border); border-radius: 12px; - background: var(--platform-subpanel-fill); + background: var(--runtime-settings-subpanel-fill); } .runtime-agent-card-summary { @@ -3723,7 +3727,7 @@ h2 { min-height: 66px; padding: 11px 18px 11px 22px; border-top: 1px solid var(--platform-line-soft); - background: var(--platform-desktop-topbar-fill); + background: var(--runtime-settings-topbar-fill); } .runtime-settings-footer .status-line { @@ -3744,7 +3748,7 @@ h2 { .runtime-settings-footer .status-line[data-tone='success'] { border-color: var(--platform-success-border); - background: var(--platform-success-fill); + background: #edf8ef; color: var(--platform-success-text); } @@ -4845,6 +4849,20 @@ iframe.preview-frame { color: var(--platform-button-secondary-text); } +.game-workbench-view-actions .game-workbench-play-button { + border-color: var(--platform-button-primary-border); + background: var(--platform-button-primary-fill); + color: var(--platform-button-primary-text); +} + +.game-workbench-view-actions .game-workbench-play-button:disabled { + border-color: var(--platform-surface-border); + background: var(--platform-button-secondary-fill); + color: var(--platform-text-muted); + cursor: not-allowed; + opacity: 0.6; +} + .game-resource-reorder-status { min-width: 0; color: #9a725f; diff --git a/apps/ai-game-creator-shell/tests/appSurface/runtime-settings.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/runtime-settings.suite.ts index 9ba8040b1..bb19d6b30 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/runtime-settings.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/runtime-settings.suite.ts @@ -456,6 +456,44 @@ export function registerRuntimeSettingsTests() { expect(screen.queryByRole('dialog', { name: '运行时配置' })).toBeNull(); }); + it('locks page scrolling while runtime settings are open and restores it after close', async () => { + const invoke = vi.fn(async (command: string) => { + if (command === 'read_game_creator_app_config') { + return { + path: '/home/test/AppData/game-creator.config.json', + config: { + agentMode: 'codex_app_server', + llm: { + apiKey: '', + baseUrl: 'https://llm.example.test/v1', + model: 'gpt-scroll-lock', + apiKind: 'openai_responses', + stream: true, + webSearchEnabled: false, + requestTimeoutMs: 180000, + maxRetries: 2, + retryBackoffMs: 500, + }, + }, + }; + } + throw new Error(`unexpected invoke ${command}`); + }); + window.__TAURI__ = { core: { invoke } }; + document.documentElement.style.overflow = 'auto'; + document.body.style.overflow = 'scroll'; + renderLauncherAt('/?launcher'); + + fireEvent.click(screen.getByRole('button', { name: '配置' })); + await screen.findByRole('dialog', { name: '运行时配置' }); + expect(document.documentElement.style.overflow).toBe('hidden'); + expect(document.body.style.overflow).toBe('hidden'); + + fireEvent.click(screen.getByRole('button', { name: '关闭 Agent 设置' })); + expect(document.documentElement.style.overflow).toBe('auto'); + expect(document.body.style.overflow).toBe('scroll'); + }); + it('configures MCP servers and reads the bounded Runner catalog', async () => { const manifest = createGameCreationAppManifest( 'local-project-draft', @@ -1227,7 +1265,7 @@ export function registerPublishedRuntimeSettingsTests() { model: 'gpt-5.6-sol', apiKind: 'openai_responses', reasoningEffort: 'max', - stream: false, + stream: true, webSearchEnabled: false, contextWindowTokens: 128000, autoCompactTokenLimit: 64000,