移除退役策划界面样式

删除旧 GDD 审批卡与策划窄条的孤儿 CSS

更新聊天布局测试以覆盖现役 DirectCodex 选择器

保留设计 Agent 和通用项目工作台表现
This commit is contained in:
2026-09-15 07:05:46 +00:00
parent 151c61ad08
commit bcbf398b65
3 changed files with 5 additions and 399 deletions
@@ -818,7 +818,6 @@ export const AGENT_RUNTIME_PLAN_SUBMIT_GDD_TOOL = 'plan.submit_gdd';
// 屏障处按信封原文构造这个 pending`ensure_static_delegate_user_input_wait_at_locked`),
// 同一份问题再投影成 `userInputRequest`,交互面是问答卡。
// - `plan.submit_gdd`:策划子 Agent 提交 Fast GDD 后,`planning/pending.json` 的
// `submission.pendingActionId` 指向的正是这个 pending,交互面是 `GddApprovalCard`
// 的批准 / 修改 / 退回。
//
// 两者都没有「确认 / 拒绝」语义:`user.input_request` 从来不在
+2 -391
View File
@@ -9269,115 +9269,6 @@ iframe.preview-frame {
}
}
/* ============================================================
立项策划前端样式(PlanGddSurface / 阶段进度 / GDD 审批卡 / 交付行 /
planning-lane-runtime-strip)。
这一段曾在 #193「Codex/agent chat layout fix」重写聊天样式时被整体误删:
组件(TSX)原样保留、选择器全数消失,策划界面裸奔、正文弹层失去 fixed 定位
变成内联平铺。从 5802048c3^ 原样恢复。聊天区样式重构时请勿顺手清理本段——
这些选择器的使用方在 features/project-workspace/GddApprovalCard.tsx 与
PlanningLaneRuntimeStrip.tsx。
============================================================ */
/* 策划区是一个面:阶段进度是标题栏,审批卡是正文。边框和圆角只画在外壳上,里面两块
不再各自带框。 */
.plan-gdd-surface {
display: grid;
min-width: 0;
border: 1px solid #cfd7e6;
border-radius: 10px;
background: #fff;
overflow: hidden;
}
.gdd-approval-card {
display: grid;
gap: 14px;
padding: 16px 18px 18px;
background: #f8fbff;
}
.plan-gdd-surface--with-card .plan-gdd-stage-progress {
border-bottom: 1px solid #dbe4f1;
}
.plan-gdd-stage-progress {
display: grid;
gap: 6px;
padding: 10px 12px;
background: #fff;
color: #526173;
font-size: 12px;
}
.plan-gdd-stage-progress__header,
.plan-gdd-stage-progress__meta {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 8px 14px;
}
/* 批准后的交付行。它是策划阶段唯一的产物出口,所以给一条分隔线把它和上面的状态
区分开,而不是混成第三行元信息。 */
.plan-gdd-stage-progress__delivery {
display: grid;
gap: 8px;
margin-top: 4px;
padding-top: 9px;
border-top: 1px solid #e6ecf5;
}
.plan-gdd-stage-progress__delivery code {
min-width: 0;
color: #3c4a5c;
font-size: 11px;
overflow-wrap: anywhere;
}
.plan-gdd-stage-progress__delivery-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.plan-gdd-stage-progress__delivery-actions button {
min-height: 30px;
padding: 0 12px;
border: 1px solid #cfd7e6;
border-radius: 6px;
color: #27364a;
background: #fff;
font-size: 12px;
}
.plan-gdd-stage-progress__delivery-actions button:hover:not(:disabled),
.plan-gdd-stage-progress__delivery-actions button:focus-visible {
border-color: #1f6feb;
color: #1f6feb;
}
.plan-gdd-stage-progress__delivery-actions button:disabled {
opacity: 0.58;
}
.plan-gdd-stage-progress__delivery-error {
color: #b42323;
overflow-wrap: anywhere;
}
.plan-gdd-stage-progress__header strong {
color: #27364a;
}
.plan-gdd-stage-progress__header span {
padding: 3px 8px;
border-radius: 999px;
background: #eef6ff;
color: #1f6feb;
}
.design-agent-approval,
.design-agent-clarify {
display: flex;
@@ -9910,283 +9801,6 @@ button.design-workspace-tree__entry:hover,
}
}
.gdd-approval-card__header {
display: grid;
gap: 5px;
min-width: 0;
}
.gdd-approval-card h2,
.gdd-approval-card h3,
.gdd-approval-card p {
margin: 0;
}
.gdd-approval-card h2 {
font-size: 18px;
}
.gdd-approval-card__header p {
color: #526173;
overflow-wrap: anywhere;
}
.gdd-approval-card__details-trace {
color: #6b7a8c;
font-size: 11px;
overflow-wrap: anywhere;
}
.gdd-approval-card__details-trigger {
justify-self: start;
min-height: 30px;
padding: 0 10px;
border: 1px solid #cfd7e6;
border-radius: 6px;
color: #27364a;
background: #fff;
}
.gdd-approval-card__decisions {
display: grid;
gap: 8px;
}
.gdd-approval-card__decisions article {
display: grid;
gap: 3px;
padding: 9px 10px;
border: 1px solid #e2e8f0;
border-radius: 7px;
background: #fff;
}
.gdd-approval-card__decisions article span {
color: #1f6feb;
font-size: 12px;
}
.gdd-approval-card__decisions article small {
color: #526173;
overflow-wrap: anywhere;
}
.gdd-approval-card__actions,
.gdd-approval-card__dialog-actions,
.gdd-approval-card__recovery {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.gdd-approval-card__actions button,
.gdd-approval-card__dialog-actions button,
.gdd-approval-card__recovery button {
min-height: 32px;
padding: 0 12px;
border: 1px solid #cfd7e6;
border-radius: 6px;
color: #fff;
background: #1f6feb;
}
.gdd-approval-card__actions button:nth-child(n + 2),
.gdd-approval-card__dialog-actions button:first-child {
color: #27364a;
background: #fff;
}
.gdd-approval-card button:disabled {
cursor: not-allowed;
opacity: 0.55;
}
.gdd-approval-card__recovery {
justify-content: space-between;
padding: 9px 10px;
border-radius: 7px;
color: #854d0e;
background: #fff7df;
font-size: 13px;
}
.gdd-approval-card__error {
padding: 9px 10px;
border-radius: 7px;
color: #991b1b;
background: #fff1f2;
overflow-wrap: anywhere;
}
.gdd-approval-card__dialog-backdrop {
position: fixed;
top: var(--window-chrome-height);
right: 0;
bottom: 0;
left: 0;
z-index: 220;
display: grid;
padding: 24px;
background: rgb(0 0 0 / 56%);
place-items: center;
}
.gdd-approval-card__dialog {
display: grid;
gap: 12px;
width: min(520px, 100%);
padding: 20px;
border: 1px solid #e5e7eb;
border-radius: 8px;
background: #fff;
box-shadow: 0 18px 52px rgb(0 0 0 / 18%);
}
.gdd-approval-card__details {
max-height: min(760px, calc(100vh - 32px));
overflow: auto;
}
.gdd-approval-card__details header,
.gdd-approval-card__details article {
display: grid;
gap: 5px;
}
.gdd-approval-card__details article {
padding-top: 10px;
border-top: 1px solid #e2e8f0;
}
.gdd-approval-card__details p {
white-space: pre-line;
overflow-wrap: anywhere;
}
.gdd-approval-card__dialog textarea {
width: 100%;
min-height: 110px;
padding: 9px;
border: 1px solid #cfd7e6;
border-radius: 6px;
resize: vertical;
}
.gdd-approval-card__dialog-hint {
padding: 9px 10px;
border-radius: 7px;
color: #854d0e;
background: #fff7df;
font-size: 13px;
}
/* 审批卡是这一列里唯一没有天花板的成员:Fast GDD 的决定项越多它越高,能把消息列表和运行
时面板一起挤出可视区。和 `.agent-runtime-status` 一样给它自己的上限加内部滚动,而不是
让它去挤别人。 */
/* 策划链路的会话列比另外两条多一个成员:策划面(阶段进度 + 审批卡)。#1935802048c3
「Codex/agent chat layout fix」)把这个容器从基础规则继承来的 `display: grid` 改成
`display: block`、并把消息列表从 `flex: 1 1 auto` 改成 `height: 100%`,于是列表独吞
整列高度,排在它后面的策划窄条、待确认命令、输入框和状态行全部被 `overflow: hidden`
静默裁掉——组件照常渲染、DOM 里查得到,只是位置落在裁剪线外,屏幕上什么都没有。
实测:窄条 top=858 而容器 bottom=788,超出 384pxscrollHeight 1235 vs clientHeight 734。
同一批改动还删掉了 `.game-workbench-chat .project-supervisor-composer` 的 4 条规则,
所以列表上那个 `padding-bottom: 196px`(本意是给「浮起来的输入框」留位)从来没有对应
的定位规则,那个模型压根没成立过。
命中判据是两个类的并集,两个都只属于策划链路,做游戏与做素材保持 master 的 block
列原样不动。为什么不能只认策划面:`PlanGddSurface` 在 `planGddState === null` 时整个
返回 null,而 `planGddState` 初值就是 null、要靠一次独立的 IPC 才填上。首帧竞态、以及
hydrate 持续失败时,策划 run 照跑、澄清卡照渲染,只认策划面就会漏掉这一格,裁剪原样
复发。窄条自己在场就等价于「有东西要用户动手」,把它并进来之后,「卡片存在」和「列
布局生效」才是同一件事。
用 flex 列而不是 grid:子元素个数随待确认命令的有无浮动,固定行模板会错位;而且下面
那条 `.plan-gdd-surface { flex: 0 0 auto }` 本来就是照 flex 写的,容器变成 flex 之后它
才真正生效——在此之前它一直是死声明。 */
.game-workbench-chat
.project-supervisor-conversation:has(
.plan-gdd-surface,
.planning-lane-runtime-strip
) {
display: flex;
flex-direction: column;
gap: 10px;
/* 兜底:正常情况下上面的行分配已经让整列放得下,这条不会产生滚动条。但审批卡展开
到 52dvh 且窄条同时在场时仍可能超出,届时给滚动而不是继承 `overflow: hidden`
的裁剪——这个 bug 的全部代价就来自「悄悄裁掉」,宁可多一根滚动条。 */
overflow-y: auto;
}
/* 整列里只有消息列表可收缩:其余成员各自有天花板(策划面按内容、窄条 52dvh 且内滚、
输入框定高),由列表吸收剩余空间。`height: 100%` 必须撤掉,否则它照旧独吞整列;
`padding-bottom` 也一并收回,输入框已经回到文档流里,不再需要给它留空。 */
.game-workbench-chat
.project-supervisor-conversation:has(
.plan-gdd-surface,
.planning-lane-runtime-strip
)
.project-supervisor-message-list {
flex: 1 1 auto;
height: auto;
min-height: 96px;
padding-bottom: 12px;
scroll-padding-bottom: 12px;
}
/* 这三个成员不参与压缩:消息列表变长时不能把它们挤没——它们正是用户唯一需要动手的
地方(澄清卡、输入框)。 */
.game-workbench-chat
.project-supervisor-conversation:has(
.plan-gdd-surface,
.planning-lane-runtime-strip
)
.planning-lane-runtime-strip,
.game-workbench-chat
.project-supervisor-conversation:has(
.plan-gdd-surface,
.planning-lane-runtime-strip
)
.project-supervisor-composer,
.game-workbench-chat
.project-supervisor-conversation:has(
.plan-gdd-surface,
.planning-lane-runtime-strip
)
.project-supervisor-workspace-status {
flex: 0 0 auto;
}
/* 这个面不参与 flex 压缩。它自己不会长高:标题栏是固定几行,审批卡下面有自己的
max-height 和内滚,所以高度天然有界。让它可压缩的话,`overflow: hidden`(画圆角
要的)会把底部切掉——批准后交付行正好在那儿,表现是路径和两个按钮凭空消失。 */
.game-workbench-chat .plan-gdd-surface {
flex: 0 0 auto;
}
/* 只有审批卡在场时才需要「标题栏定高 + 正文占余下」的两行轨道。批准后卡片收掉,
面里只剩标题栏,这条声明会给它套上一个不存在的第二行。 */
.game-workbench-chat .plan-gdd-surface--with-card {
min-height: 0;
grid-template-rows: auto minmax(0, 1fr);
}
.game-workbench-chat .gdd-approval-card {
min-height: 0;
max-height: clamp(240px, 52dvh, 640px);
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-gutter: stable;
}
/* 上面 24dvh/240px 的天花板是给做游戏链路常驻的调试面板设的。策划链路的窄条只在
需要用户动手时出现(澄清卡 / 失败恢复),内容是要读完再回答的题面,给它和审批
卡同级的空间。 */
.game-workbench-chat .planning-lane-runtime-strip {
max-height: clamp(240px, 52dvh, 640px);
}
/* 做方案在拿到第一个已登记资源之前,左边的资源画布是空的;工作台此时收成单栏,
对话铺满。类名由 view/project-development/index.tsx 的 conversationOnlyWorkbench
拼上(planningStartMode && resources.length === 0),画布是 display: none 不是
@@ -10675,11 +10289,8 @@ button.design-workspace-tree__entry:hover,
color: var(--platform-button-primary-text);
}
/* 对话框盒子的最终几何,故意放在文件靠后的位置:它与上面那条同选择器同权重
`.game-workbench-chat .project-supervisor-surface.is-direct-codex
.project-supervisor-message-list`),按"后写胜出"把两处会顶掉它的规则压回去——
一是 `:has(.plan-gdd-surface, .planning-lane-runtime-strip)` 给列表留的
`padding-bottom: 12px`,二是下面窄屏块之前可能出现的任何底边偏移。
/* 对话框盒子的最终几何,故意放在文件靠后的位置:它与上面同选择器同权重,按
"后写胜出"把窄屏块之前可能出现的任何底边偏移压回去。
这里曾经是一条 `bottom: 156px`"列表在上、输入区在下"那版两盒布局的残留:给下面那只
浮起来的输入区预留高度),它把上面那条 `bottom: 0` 悄悄顶掉,外框底边落在输入区腰上、
输入区下半截露在框外——用户看到的就是"外框底边与输入区压在一起、没把输入区包住"。
@@ -112,10 +112,6 @@ const COMPOSER_EDITOR = `${COMPOSER_PLAIN} .resource-reference-input-editor`;
const COMPOSER_CONTROLS = `${COMPOSER} .project-supervisor-composer-controls`;
const COMPOSER_SUBMIT = `${COMPOSER_CONTROLS} .project-supervisor-submit-button`;
const INPUT_ACTIONS = `${COMPOSER} .resource-reference-input-actions`;
// 策划链在会话列里额外挂了一条规划面/窄条时,列表会命中这条 `:has(...)` 规则——
// 它同样声明了 `padding-bottom`,正是上一轮把留白改回 12px 的那种隐患。
const LIST_WITH_PLAN_SURFACE = `.game-workbench-chat .project-supervisor-conversation:has(.plan-gdd-surface, .planning-lane-runtime-strip) .project-supervisor-message-list`;
const DESKTOP = 1440;
const MOBILE = 390;
@@ -186,7 +182,7 @@ function composerMaxHeight() {
describe('陶泥儿对话区:外框完整包住输入区', () => {
it('外框四边贴会话区,输入区四边都在外框之内且不重合(宽屏)', () => {
const list = desktopDeclarations(MESSAGE_LIST, LIST_WITH_PLAN_SURFACE);
const list = desktopDeclarations(MESSAGE_LIST);
const composer = desktopDeclarations(COMPOSER, COMPOSER_PLAIN);
// 先看不重合关系再钉绝对位移:底边必须"外框在外、输入区在内",留白 > 0。
@@ -238,7 +234,7 @@ describe('陶泥儿对话区:外框完整包住输入区', () => {
});
it('消息列表底部留白 = 输入区内缩 + 输入区最高高度 + 间距,且与 scroll-padding 同值', () => {
const list = desktopDeclarations(MESSAGE_LIST, LIST_WITH_PLAN_SURFACE);
const list = desktopDeclarations(MESSAGE_LIST);
const composer = desktopDeclarations(COMPOSER, COMPOSER_PLAIN);
const { total, actionsRowHeight } = composerMaxHeight();
@@ -260,7 +256,7 @@ describe('陶泥儿对话区:外框完整包住输入区', () => {
it('窄屏把外框交给会话列,输入区回到文档流,四周仍有一圈边距(390px)', () => {
const conversation = mobileDeclarations(CONVERSATION);
const list = mobileDeclarations(MESSAGE_LIST, LIST_WITH_PLAN_SURFACE);
const list = mobileDeclarations(MESSAGE_LIST);
const composer = mobileDeclarations(
COMPOSER,
COMPOSER_PLAIN,