策划列布局的命中判据补上窄条,hydrate 还没回来时澄清卡不再被裁
上一笔只用 `:has(.plan-gdd-surface)` 认策划链路,漏了一格:`PlanGddSurface` 在 `planGddState === null` 时整个返回 null,而 `planGddState` 初值就是 null,要靠 `hydrate_game_creator_plan_gdd_state` 这一次独立 IPC 才填上。首帧竞态、以及 hydrate 持续失败(非写锁争用的错误会把 state 留在 null)这两种情形下,策划 run 照跑、 `PlanningLaneRuntimeStrip` 照渲染澄清卡,但容器上的 `:has()` 不命中,#193 那套 `display: block` + 列表 `height: 100%` + `overflow: hidden` 原样回来,卡片又被静默裁到 可视区外。 判据改成 `.plan-gdd-surface` 与 `.planning-lane-runtime-strip` 的并集。两个类都只属于 策划链路,做游戏与做素材仍走 master 的 block 列。窄条在场本身就等价于「有东西要用户 动手」,并进来之后「卡片存在」和「列布局生效」是同一件事,不再依赖另一条异步链路的 时序。 守门加在已有的策划样式测试里(同一处已经钉着 #193 误删的几条规则):断言这条 flex 列 规则的 `:has()` 必须包含窄条类。已验证非空转——把并集改回单一类,这条断言变红。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7517,11 +7517,21 @@ iframe.preview-frame {
|
||||
所以列表上那个 `padding-bottom: 196px`(本意是给「浮起来的输入框」留位)从来没有对应
|
||||
的定位规则,那个模型压根没成立过。
|
||||
|
||||
`:has(.plan-gdd-surface)` 只在策划面在场时命中,做游戏与做素材保持 master 的 block
|
||||
列原样不动。用 flex 列而不是 grid:子元素个数随待确认命令的有无浮动,固定行模板会
|
||||
错位;而且下面那条 `.plan-gdd-surface { flex: 0 0 auto }` 本来就是照 flex 写的,容器
|
||||
变成 flex 之后它才真正生效——在此之前它一直是死声明。 */
|
||||
.game-workbench-chat .project-supervisor-conversation:has(.plan-gdd-surface) {
|
||||
命中判据是两个类的并集,两个都只属于策划链路,做游戏与做素材保持 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;
|
||||
@@ -7535,7 +7545,10 @@ iframe.preview-frame {
|
||||
输入框定高),由列表吸收剩余空间。`height: 100%` 必须撤掉,否则它照旧独吞整列;
|
||||
`padding-bottom` 也一并收回,输入框已经回到文档流里,不再需要给它留空。 */
|
||||
.game-workbench-chat
|
||||
.project-supervisor-conversation:has(.plan-gdd-surface)
|
||||
.project-supervisor-conversation:has(
|
||||
.plan-gdd-surface,
|
||||
.planning-lane-runtime-strip
|
||||
)
|
||||
.project-supervisor-message-list {
|
||||
flex: 1 1 auto;
|
||||
height: auto;
|
||||
@@ -7547,13 +7560,22 @@ iframe.preview-frame {
|
||||
/* 这三个成员不参与压缩:消息列表变长时不能把它们挤没——它们正是用户唯一需要动手的
|
||||
地方(澄清卡、输入框)。 */
|
||||
.game-workbench-chat
|
||||
.project-supervisor-conversation:has(.plan-gdd-surface)
|
||||
.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)
|
||||
.project-supervisor-conversation:has(
|
||||
.plan-gdd-surface,
|
||||
.planning-lane-runtime-strip
|
||||
)
|
||||
.project-supervisor-composer,
|
||||
.game-workbench-chat
|
||||
.project-supervisor-conversation:has(.plan-gdd-surface)
|
||||
.project-supervisor-conversation:has(
|
||||
.plan-gdd-surface,
|
||||
.planning-lane-runtime-strip
|
||||
)
|
||||
.project-supervisor-workspace-status {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
@@ -578,5 +578,13 @@ export function registerPlanGddApprovalTests() {
|
||||
expect(styles).toMatch(
|
||||
/\.game-workbench-layout\.is-conversation-only \.game-workbench-stage\s*\{[^}]*display:\s*none/s,
|
||||
);
|
||||
// 工作台里的会话列是 `overflow: hidden` 的定高列。策划链路比另外两条多出窄条
|
||||
// (澄清卡 / 失败恢复),只有把这一列排成 flex 列、窄条不参与压缩,它才落在可视
|
||||
// 区里;否则组件照常渲染却被静默裁到线外,屏幕上什么都没有。命中判据必须包含窄条
|
||||
// 自身——只认 `.plan-gdd-surface` 时,`planGddState` 还没 hydrate 出来的那一格里
|
||||
// 澄清卡照样被裁。
|
||||
expect(styles).toMatch(
|
||||
/\.game-workbench-chat\s+\.project-supervisor-conversation:has\([^)]*\.planning-lane-runtime-strip[^)]*\)\s*\{[^}]*display:\s*flex/s,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user