From 1d6cbd4b674add17d6170be82ff669d73eadcc54 Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Tue, 29 Sep 2026 19:35:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=96=E5=A3=B3=E7=8A=B6=E6=80=81=E6=A0=8F?= =?UTF-8?q?=E9=80=80=E5=BD=B9=EF=BC=8C=E7=8A=B6=E6=80=81=E6=94=B9=E7=94=B1?= =?UTF-8?q?=E6=B5=AE=E5=B1=82=E6=8F=90=E7=A4=BA=E6=89=BF=E8=BD=BD=20-=20?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=E8=BE=93=E5=85=A5=E6=A1=86=E4=B8=8B=E6=96=B9?= =?UTF-8?q?=E4=B8=8E=E9=A1=B9=E7=9B=AE=E7=BB=84=E9=A1=B5=E9=9D=A2=E5=A4=B4?= =?UTF-8?q?=E9=83=A8=E9=82=A3=E8=A1=8C=E7=8A=B6=E6=80=81=E6=A0=8F=E9=80=80?= =?UTF-8?q?=E5=BD=B9=EF=BC=9Astatus=20=E4=B8=8D=E5=86=8D=E7=94=B1=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=B8=B2=E6=9F=93=EF=BC=8C=E7=BB=9F=E4=B8=80=E7=94=B1?= =?UTF-8?q?=E5=A4=96=E5=A3=B3=E6=B5=AE=E5=B1=82=E6=89=BF=E8=BD=BD=EF=BC=88?= =?UTF-8?q?WorkspaceLauncher=20=E5=90=88=E6=88=90=E7=B2=98=E6=80=A7?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=B8=8E=E4=B8=80=E6=AC=A1=E6=80=A7=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=EF=BC=8C=E6=B8=B2=E6=9F=93=20notice=20=3F=3F=20status?= =?UTF-8?q?Notice=EF=BC=89=20-=20=E8=BF=9B=E8=A1=8C=E4=B8=AD=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=E4=B8=8E=E5=A4=B1=E8=B4=A5=E7=BB=93=E8=AE=BA=E8=B5=B0?= =?UTF-8?q?=E7=B2=98=E6=80=A7=E6=B5=AE=E5=B1=82=EF=BC=88sticky:=20true?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E8=87=AA=E5=8A=A8=E6=94=B6=E8=B5=B7=EF=BC=8C?= =?UTF-8?q?=E5=88=87=E9=A1=B5=E5=9B=9E=E6=9D=A5=E4=BB=8D=E5=8F=AF=E8=A7=81?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E6=88=90=E5=8A=9F=E4=B8=8E=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E5=9B=9E=E6=98=BE=E8=B5=B0=E4=B8=80=E6=AC=A1=E6=80=A7=E6=B5=AE?= =?UTF-8?q?=E5=B1=82=EF=BC=88=E6=88=90=E5=8A=9F/=E5=8F=96=E6=B6=88=202.6?= =?UTF-8?q?=20=E7=A7=92=E3=80=81=E5=A4=B1=E8=B4=A5=206=20=E7=A7=92?= =?UTF-8?q?=E6=94=B6=E8=B5=B7=EF=BC=89=EF=BC=8C=E4=B8=80=E6=AC=A1=E6=80=A7?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BC=98=E5=85=88=E6=98=BE=E7=A4=BA=EF=BC=8C?= =?UTF-8?q?=E6=94=B6=E8=B5=B7=E5=90=8E=E7=B2=98=E6=80=A7=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E6=98=BE=E7=A4=BA=20-=20=E7=B2=98=E6=80=A7?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=8F=AA=E6=8C=82=E9=A6=96=E9=A1=B5=E4=B8=8E?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=BB=84=E4=B8=A4=E4=B8=AA=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=EF=BC=8C=E8=BF=9B=E9=A1=B9=E7=9B=AE=E5=B7=A5=E4=BD=9C=E5=8F=B0?= =?UTF-8?q?=E3=80=81=E6=A8=A1=E6=9D=BF=E5=BA=93=E3=80=81=E5=B8=AE=E5=8A=A9?= =?UTF-8?q?=E9=A1=B5=E4=B8=8D=E5=86=8D=E9=A3=98=E5=9C=A8=E7=95=8C=E9=9D=A2?= =?UTF-8?q?=E4=B8=8A=EF=BC=9B=E8=BF=90=E8=A1=8C/=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=B8=8E=E5=8F=96=E6=B6=88=E5=9B=9E=E6=98=BE?= =?UTF-8?q?=E4=B8=8D=E5=8F=97=E8=AF=A5=E9=99=90=E5=88=B6=20-=20RunNoticeTo?= =?UTF-8?q?ast/RunNotice=20=E6=9B=B4=E5=90=8D=E4=B8=BA=20LauncherNoticeToa?= =?UTF-8?q?st/LauncherNotice=EF=BC=8C=E6=96=B0=E5=A2=9E=20sticky=20?= =?UTF-8?q?=E4=B8=8E=20neutral=20=E8=89=B2=E8=B0=83=EF=BC=8C=E6=8C=82?= =?UTF-8?q?=E7=82=B9=E6=94=B9=E4=B8=BA=20data-launcher-notice-toast?= =?UTF-8?q?=EF=BC=8C=E9=95=BF=E6=96=87=E6=A1=88=E5=AE=B9=E5=99=A8=E9=99=90?= =?UTF-8?q?=E5=AE=BD=20min(680px,=20100vw=20-=202rem)=20=E5=B9=B6=E6=8D=A2?= =?UTF-8?q?=E8=A1=8C=20-=20=E6=94=B6=E8=B5=B7=E5=9B=9E=E8=B0=83=E5=8F=AA?= =?UTF-8?q?=E4=BB=8E=20ref=20=E8=AF=BB=EF=BC=8C=E4=B8=8D=E5=86=8D=E5=86=99?= =?UTF-8?q?=E8=BF=9B=20effect=20=E4=BE=9D=E8=B5=96=EF=BC=9A=E6=AD=A4?= =?UTF-8?q?=E5=89=8D=E5=A4=96=E5=A3=B3=E6=AF=8F=E6=AC=A1=E9=87=8D=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E9=83=BD=E4=BC=9A=E6=8D=A2=E4=B8=80=E4=B8=AA=E5=86=85?= =?UTF-8?q?=E8=81=94=E7=AE=AD=E5=A4=B4=E5=87=BD=E6=95=B0=EF=BC=8C=E6=8A=8A?= =?UTF-8?q?=E6=94=B6=E8=B5=B7=E8=AE=A1=E6=97=B6=E9=87=8D=E6=96=B0=E8=B5=B7?= =?UTF-8?q?=E7=AE=97=EF=BC=8C=E9=95=BF=E9=A9=BB=E9=A1=B5=E9=9D=A2=E4=B8=8A?= =?UTF-8?q?=E7=9A=84=E6=8F=90=E7=A4=BA=E5=8F=AF=E8=83=BD=E6=B0=B8=E8=BF=9C?= =?UTF-8?q?=E6=94=B6=E4=B8=8D=E5=9B=9E=E5=8E=BB=20-=20useHomeProjectCreati?= =?UTF-8?q?on=20=E4=B8=89=E5=A4=84=E5=8F=96=E6=B6=88=EF=BC=88=E9=9D=9E?= =?UTF-8?q?=E7=A9=BA=E6=96=87=E4=BB=B6=E5=A4=B9=E7=A1=AE=E8=AE=A4=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E3=80=81=E6=89=93=E5=BC=80=E9=A1=B9=E7=9B=AE=E9=80=89?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E3=80=81=E6=96=B0=E5=BB=BA=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E9=80=89=E7=9B=AE=E5=BD=95=EF=BC=89=E6=94=B9=E4=B8=BA=E6=B8=85?= =?UTF-8?q?=E7=A9=BA=E7=8A=B6=E6=80=81=E5=B9=B6=E5=BC=B9=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=E6=80=A7=E6=B5=AE=E5=B1=82=E5=9B=9E=E6=98=BE=E3=80=8C=E5=B7=B2?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E3=80=8D=EF=BC=8C=E4=B8=8D=E5=86=8D=E5=BE=80?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E4=B8=8A=E9=82=A3=E8=A1=8C=E5=86=99=E6=96=87?= =?UTF-8?q?=E5=AD=97=20-=20=E5=88=A0=E9=99=A4=20HomeView=20=E7=9A=84=20sta?= =?UTF-8?q?tus=20prop=20=E4=B8=8E=E7=8A=B6=E6=80=81=E8=A1=8C=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E3=80=81ProjectsPage=20=E7=9A=84=20status=20prop=20?= =?UTF-8?q?=E4=B8=8E=20.launcher-project-page-status=20=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=8F=8A=E5=AF=B9=E5=BA=94=20CSS=20=E8=A7=84=E5=88=99=20-=20la?= =?UTF-8?q?uncherNoticeToast=20=E7=94=A8=E4=BE=8B=E8=A1=A5=E7=B2=98?= =?UTF-8?q?=E6=80=A7=E4=B8=8D=E6=94=B6=E8=B5=B7=E3=80=81=E7=88=B6=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E9=87=8D=E6=B8=B2=E6=9F=93=E4=B8=8D=E9=87=8D=E6=96=B0?= =?UTF-8?q?=E8=AE=A1=E6=97=B6=E3=80=81=E5=8F=96=E6=B6=88=E5=9B=9E=E6=98=BE?= =?UTF-8?q?=E7=9F=AD=E6=97=B6=E6=94=B6=E8=B5=B7=EF=BC=9BlauncherNoticeShel?= =?UTF-8?q?lWiring=20=E7=94=A8=E4=BE=8B=E8=A1=A5=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=B8=AD=E7=8A=B6=E6=80=81=E4=B8=8E=E5=8F=96=E6=B6=88=E5=9B=9E?= =?UTF-8?q?=E6=98=BE=E9=83=BD=E5=8F=AA=E8=B5=B0=E6=B5=AE=E5=B1=82=E3=80=81?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=E4=B8=8D=E7=95=99=E9=82=A3=E4=B8=80=E8=A1=8C?= =?UTF-8?q?=E3=80=81=E7=B2=98=E6=80=A7=E7=8A=B6=E6=80=81=E4=B8=8D=E8=BF=9B?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=B7=A5=E4=BD=9C=E5=8F=B0=20-=20appSurface/?= =?UTF-8?q?home.suite=20=E4=B8=89=E5=A4=84=E5=8F=96=E6=B6=88=E6=96=AD?= =?UTF-8?q?=E8=A8=80=E6=94=B9=E6=96=AD=E6=B5=AE=E5=B1=82=E6=8C=82=E7=82=B9?= =?UTF-8?q?=EF=BC=9BhomeWebPreflight=20=E4=B8=8E=20designProjectRestore=20?= =?UTF-8?q?=E7=9A=84=20hook=20=E5=A4=B9=E5=85=B7=E8=A1=A5=20showTransientN?= =?UTF-8?q?otice=20-=20=E6=8A=80=E6=9C=AF=E6=96=B9=E6=A1=88=E4=B8=8E=20dec?= =?UTF-8?q?ision-log=20=E8=AE=B0=E5=BD=95=E8=AF=A5=E5=8F=A3=E5=BE=84?= =?UTF-8?q?=E4=B8=8E=E8=BE=B9=E7=95=8C=EF=BC=9A=E9=A6=96=E9=A1=B5=E5=B8=A6?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E7=9A=84=E3=80=8C=E5=B7=B2=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E7=9A=84=E5=B7=A5=E4=BD=9C=E5=8C=BA=E3=80=8D=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BB=8D=E7=95=99=E5=9C=A8=E9=A1=B5=E9=9D=A2=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app-shell/LauncherNoticeToast.tsx | 91 +++++++++++++++++++ .../features/app-shell/ProjectCreation.tsx | 7 -- .../src/features/app-shell/RunNoticeToast.tsx | 70 -------------- .../features/app-shell/WorkspaceLauncher.tsx | 62 ++++++++++--- .../src/features/app-shell/model.ts | 16 ++++ .../app-shell/useHomeProjectCreation.ts | 19 +++- apps/ai-game-creator-shell/src/styles.css | 4 - .../src/view/home/index.tsx | 14 +-- .../tests/appSurface/home.suite.ts | 21 ++++- .../tests/designProjectRestore.test.tsx | 1 + .../tests/homeWebPreflight.test.tsx | 1 + ...tsx => launcherNoticeShellWiring.test.tsx} | 85 +++++++++++++++-- ....test.tsx => launcherNoticeToast.test.tsx} | 76 ++++++++++++++-- .../shared-memory/decision-log.md | 14 ++- ...¹案】AI游戏创作智能体App实施计划-2026-06-24.md | 1 + 15 files changed, 358 insertions(+), 124 deletions(-) create mode 100644 apps/ai-game-creator-shell/src/features/app-shell/LauncherNoticeToast.tsx delete mode 100644 apps/ai-game-creator-shell/src/features/app-shell/RunNoticeToast.tsx rename apps/ai-game-creator-shell/tests/{runNoticeShellWiring.test.tsx => launcherNoticeShellWiring.test.tsx} (61%) rename apps/ai-game-creator-shell/tests/{runNoticeToast.test.tsx => launcherNoticeToast.test.tsx} (56%) diff --git a/apps/ai-game-creator-shell/src/features/app-shell/LauncherNoticeToast.tsx b/apps/ai-game-creator-shell/src/features/app-shell/LauncherNoticeToast.tsx new file mode 100644 index 000000000..156322c7e --- /dev/null +++ b/apps/ai-game-creator-shell/src/features/app-shell/LauncherNoticeToast.tsx @@ -0,0 +1,91 @@ +import { PlatformRuntimeStatusToast } from '@genarrative/shared/components'; +import { useEffect, useRef } from 'react'; +import { createPortal } from 'react-dom'; + +import type { LauncherNoticeTone } from './model'; + +/** + * 一次性提示的时长:成功一闪而过就够;失败要留得够久,用户得看清是什么没跑起来。 + * + * 「运行 / 预览失败」这类错误已经不再写对话区(那里只保留对话内容),所以这枚 toast 是它 + * 唯一的出口——2.6 秒对错误太短。「已取消」这类回显也走同一套时长:它是「什么都没发生」, + * 不需要用户回头再看。承接原状态栏的状态不在这张表里,它们走 `sticky`。 + */ +const LAUNCHER_NOTICE_MILLIS: Record = { + success: 2600, + neutral: 2600, + error: 6000, +}; + +export type LauncherNotice = { + /** 每次提示自增,保证重复触发同一个文案时也会重新弹一次。 */ + id: number; + message: string; + tone?: LauncherNoticeTone; + /** + * 粘性提示不自动收起,直到被下一条提示替换。 + * + * 原来那行状态栏(进行中进度、失败结论)就是这种生存期:它要能被回头看见,不能自己消失; + * 只有「已取消」这类一次性回显才到点收起。 + */ + sticky?: boolean; +}; + +/** + * 外壳级浮层提示。 + * + * 承接三类反馈,页面上都不留文字: + * 1. 运行 / 预览类动作——以前以 assistant 消息写进对话区,会一直堆在对话底部挡住运行画面; + * 运行页的预览地址改用顶栏的「在浏览器打开」。 + * 2. 状态栏里的状态(进行中进度、失败结论、成功回显)——以前常驻在首页输入框下方和项目组页面 + * 头部那一行;现在走粘性浮层,语义不变(被下一条状态替换或清空时才消失)。 + * 3. 「已取消」这类一次性回显——到点自动收起。 + */ +export function LauncherNoticeToast({ + notice, + onDismiss, +}: { + notice: LauncherNotice | null; + onDismiss: () => void; +}) { + /** + * 收起回调只从 ref 读:外壳每渲染一次就会换一个内联箭头函数,把它写进 effect 依赖会 + * 让计时器在每次重渲染时重新起算——长驻页面上的提示就永远收不回去了。 + */ + const onDismissRef = useRef(onDismiss); + onDismissRef.current = onDismiss; + useEffect(() => { + if (!notice || notice.sticky) { + return; + } + const timer = window.setTimeout( + () => onDismissRef.current(), + LAUNCHER_NOTICE_MILLIS[notice.tone ?? 'success'], + ); + return () => { + window.clearTimeout(timer); + }; + }, [notice]); + + if (!notice) { + return null; + } + return createPortal( +
+ + {notice.message} + +
, + document.body, + ); +} diff --git a/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx b/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx index c6b9a06c1..925a01cd9 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx +++ b/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx @@ -180,11 +180,9 @@ function ProjectMoreMenu({ } export function ProjectsPage({ - status, homeProject, recentProjects, }: { - status: string; homeProject: HomeProjectCreationController; recentProjects: RecentProjectsController; }) { @@ -249,11 +247,6 @@ export function ProjectsPage({

项目

-

- {recentProjects.recentWorkspaceRefreshing - ? '正在检查项目状态' - : status} -