Skip to content

Commit 1552cb3

Browse files
wehosHongzhi Wenclaude
authored
fix(chat): 退掉独立 /chat 的 full 玻璃壳,直接复用共用 compact(消除加载 full→compact 闪帧) (#1594)
chat.html 的 body 带 subtitle-web-host,static/css/index.css 早就为该 shell 写好 整套 compact 胶囊规则;但 chat.html 自己 style 里还留着一套覆盖全窗口的玻璃面板 ——选择器不带 data-chat-surface-mode 门槛、overlay 又没 hidden,于是页面一加载、 React 还没挂载时就先画出空玻璃面板,挂载后才塌成 compact,就是用户看到的先 full 再 compact 那一帧。这套 full chrome 与 index.css 的 compact 规则纯属冗余且互相打架。 - overlay 加 hidden(与 index.html 一致):挂载完成 openWindow() 才显示,挂载前不 渲染任何东西。 - 删掉 full 形态资源:#react-chat-window-shell 的 inset:40px 全窗口玻璃壳、顶栏 chrome、暗色顶栏底、#react-chat-window-root 四边渐隐 mask、liquidFlow/lightSweep 关键帧、::before/::after 玻璃层、is-collapsing/is-expanding/is-minimized 全窗口 几何复位。原地留注释存档;shell 落回 index.css 共用 compact 规则。 - test_react_chat_window_static.py:原测试把 full mask 当契约写死,改成反向断言 full 资源已退环境 + overlay 带 hidden。 保留 legacy #chat-container(app-*.js 仍 getElementById 引用)与 galgame/附件 min-height 兜底(compact 下被 index.css min-height:0 覆盖,无害)。 Co-authored-by: Hongzhi Wen <cartabio.coder1@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 9789749 commit 1552cb3

2 files changed

Lines changed: 46 additions & 146 deletions

File tree

templates/chat.html

Lines changed: 24 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -33,54 +33,27 @@
3333
background: transparent !important;
3434
overflow: hidden;
3535
}
36-
/* Electron 独立窗口模式:React Chat 覆盖全窗口 */
36+
/* Electron 独立窗口:overlay 充满窗口、当透明容器;内部 #react-chat-window-shell
37+
走与首页共用的 compact 胶囊样式(static/css/index.css 里
38+
body.subtitle-web-host #react-chat-window-shell[data-chat-surface-mode="compact"]
39+
规则集,chat.html 的 <body> 带 subtitle-web-host 故自动命中)。 */
3740
#react-chat-window-overlay {
3841
position: fixed; inset: 0;
3942
display: block !important;
4043
background: transparent !important;
4144
}
4245
#react-chat-window-backdrop { display: none !important; }
43-
#react-chat-window-shell:not(.is-minimized):not(.is-collapsing):not(.is-expanding) {
44-
position: fixed !important;
45-
inset: 40px 25px 25px 20px !important;
46-
width: auto !important; height: auto !important;
47-
max-width: none !important; max-height: none !important;
48-
transform: none !important;
49-
border-radius: 22px !important;
50-
background: transparent !important;
51-
/* 液态边缘反光 — 顶部最亮,左次之,模拟顶光 */
52-
border-top: 2px solid rgba(255, 255, 255, 0.7) !important;
53-
border-left: 1px solid rgba(255, 255, 255, 0.35) !important;
54-
border-right: 1px solid rgba(255, 255, 255, 0.15) !important;
55-
border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important;
56-
/* 外阴影 + 内高光带 */
57-
box-shadow:
58-
0 4px 16px rgba(12, 20, 34, 0.18),
59-
0 1px 4px rgba(12, 20, 34, 0.1),
60-
inset 0 2px 4px rgba(255, 255, 255, 0.5),
61-
inset 0 -1px 2px rgba(255, 255, 255, 0.08) !important;
62-
}
63-
/* 顶栏:降低透明度 + 减小高度(原 min-height:54px + padding:10px 14px 8px) */
64-
.window-topbar {
65-
background: rgba(255, 255, 255, 0.35) !important;
66-
min-height: 45px !important;
67-
height: 45px !important;
68-
padding: 0 12px !important;
69-
box-sizing: border-box !important;
70-
}
71-
.window-topbar-actions,
72-
.window-topbar-actions > * {
73-
display: flex !important;
74-
align-items: center !important;
75-
}
76-
/* 右上角四个按钮居中对齐 topbar(原 top:10px 基于 54px 高度,现适配 45px) */
77-
#react-chat-window-header-actions {
78-
top: 5px !important;
79-
}
80-
#reactChatWindowCloseButton {
81-
position: relative !important;
82-
top: -2px !important;
83-
}
46+
/* ──────────────────────────────────────────────────────────────────────
47+
full 形态(覆盖全窗口的玻璃面板)已退环境,仅在此留档:
48+
旧版在这里把 #react-chat-window-shell 钉成 inset:40px 的全窗口玻璃面板
49+
(磨砂背景 / 四边反光边框 / 外阴影 + ::before 静态高光 + ::after 流光动画
50+
+ 顶栏 chrome + #react-chat-window-root 四边渐隐 mask)。因为这些规则不带
51+
data-chat-surface-mode 门槛、且 overlay 又不是 hidden,页面一加载、React 还
52+
没挂载时就会先画出这块空的全窗口玻璃面板,挂载后才塌成 compact —— 就是
53+
"先 full 再 compact" 的那一帧。现在 shell 直接复用 index.css 的 compact 胶囊
54+
规则(透明壳 + 隐藏顶栏按钮 + 去掉 ::before/::after 玻璃层),不再注入任何
55+
full 形态样式/动画/mask 资源。
56+
────────────────────────────────────────────────────────────────────── */
8457
body.yui-guide-chat-buttons-disabled #react-chat-window-shell button,
8558
body.yui-guide-chat-buttons-disabled #toggle-chat-btn {
8659
pointer-events: none !important;
@@ -282,95 +255,11 @@
282255
'Hiragino Sans', 'Malgun Gothic', sans-serif !important;
283256
font-weight: 400 !important;
284257
}
285-
[data-theme="dark"] .window-topbar {
286-
background: rgba(50, 50, 72, 0.35) !important;
287-
}
288-
/* 四边透明度渐变带:窄边(~10px),让边缘内容淡出露出高光 */
289-
#react-chat-window-root {
290-
-webkit-mask-image:
291-
linear-gradient(to bottom, rgba(0,0,0,0.3) 0px, black 10px, black calc(100% - 10px), rgba(0,0,0,0.6) 100%),
292-
linear-gradient(to right, rgba(0,0,0,0.4) 0px, black 8px, black calc(100% - 8px), rgba(0,0,0,0.4) 100%) !important;
293-
-webkit-mask-composite: source-in !important;
294-
}
295-
body.electron-chat-window.subtitle-web-host #react-chat-window-shell[data-chat-surface-mode="compact"] #react-chat-window-root {
296-
-webkit-mask-image: none !important;
297-
mask-image: none !important;
298-
-webkit-mask-composite: initial !important;
299-
mask-composite: initial !important;
300-
}
301-
@keyframes liquidFlow {
302-
0% { background-position: 0% 0%, 80% 10%, 40% 30%, 90% 50%, 20% 70%, 60% 85%, 95% 90%; }
303-
12% { background-position: 50% 15%, 20% 60%, 80% 10%, 40% 80%, 70% 5%, 10% 50%, 55% 35%; }
304-
25% { background-position: 90% 55%, 50% 90%, 15% 65%, 75% 20%, 45% 85%, 85% 15%, 20% 70%; }
305-
38% { background-position: 30% 85%, 85% 30%, 60% 95%, 10% 45%, 90% 40%, 40% 70%, 70% 10%; }
306-
50% { background-position: 70% 40%, 10% 75%, 95% 20%, 55% 90%, 15% 30%, 75% 55%, 35% 80%; }
307-
63% { background-position: 15% 70%, 65% 15%, 30% 50%, 85% 65%, 55% 95%, 25% 25%, 80% 50%; }
308-
75% { background-position: 80% 25%, 35% 85%, 70% 40%, 20% 10%, 85% 60%, 50% 90%, 10% 30%; }
309-
88% { background-position: 45% 90%, 90% 45%, 10% 75%, 60% 35%, 30% 50%, 80% 10%, 50% 65%; }
310-
100% { background-position: 0% 0%, 80% 10%, 40% 30%, 90% 50%, 20% 70%, 60% 85%, 95% 90%; }
311-
}
312-
/* 对角光带扫过 */
313-
@keyframes lightSweep {
314-
0% { background-position: -150% -150%; }
315-
100% { background-position: 250% 250%; }
316-
}
317-
/* 静态边缘高光层 — 在内容之下 */
318-
#react-chat-window-shell:not(.is-minimized)::before {
319-
content: '' !important;
320-
position: absolute !important;
321-
inset: 0 !important;
322-
border-radius: 22px !important;
323-
pointer-events: none !important;
324-
z-index: 0 !important;
325-
/* 边缘高光 */
326-
box-shadow:
327-
inset 0 2px 6px rgba(255, 255, 255, 0.5),
328-
inset 0 -1px 3px rgba(255, 255, 255, 0.1),
329-
inset 2px 0 4px rgba(255, 255, 255, 0.15),
330-
inset -2px 0 4px rgba(255, 255, 255, 0.08) !important;
331-
/* 顶部弧形高光(静态) */
332-
background: linear-gradient(
333-
180deg,
334-
rgba(255, 255, 255, 0.25) 0%,
335-
rgba(255, 255, 255, 0.08) 8%,
336-
transparent 20%,
337-
transparent 85%,
338-
rgba(255, 255, 255, 0.04) 100%
339-
) !important;
340-
}
341-
/* 流动光斑层 — 三色径向渐变缓慢漂移,模拟玻璃折射
342-
用 background-image 而非 background 简写,避免 !important 锁死 background-position */
343-
#react-chat-window-shell:not(.is-minimized)::after {
344-
content: '' !important;
345-
position: absolute !important;
346-
inset: 0 !important;
347-
border-radius: 22px !important;
348-
pointer-events: none !important;
349-
z-index: 10 !important;
350-
background-image:
351-
radial-gradient(circle at 15% 10%, rgba(100,180,255,0.14) 0%, transparent 22%),
352-
radial-gradient(circle at 75% 15%, rgba(180,140,255,0.11) 0%, transparent 20%),
353-
radial-gradient(circle at 40% 35%, rgba(220,140,240,0.12) 0%, transparent 18%),
354-
radial-gradient(circle at 85% 50%, rgba(120,200,255,0.13) 0%, transparent 20%),
355-
radial-gradient(circle at 25% 65%, rgba(200,160,255,0.10) 0%, transparent 19%),
356-
radial-gradient(circle at 60% 80%, rgba(100,190,255,0.12) 0%, transparent 21%),
357-
radial-gradient(circle at 90% 85%, rgba(240,150,200,0.10) 0%, transparent 17%) !important;
358-
background-size: 200% 200%, 200% 200%, 200% 200%, 200% 200%, 200% 200%, 200% 200%, 200% 200% !important;
359-
background-repeat: no-repeat !important;
360-
animation: liquidFlow 20s ease-in-out infinite !important;
361-
}
362-
/* 折叠/展开动画期间:允许 JS 控制 position/size/transform */
363-
#react-chat-window-shell.is-collapsing,
364-
#react-chat-window-shell.is-expanding {
365-
inset: auto !important;
366-
max-width: none !important; max-height: none !important;
367-
border-radius: 22px !important;
368-
}
369-
/* 最小化态 */
370-
#react-chat-window-shell.is-minimized {
371-
inset: auto !important;
372-
max-width: none !important; max-height: none !important;
373-
}
258+
/* full 形态的暗色顶栏底、#react-chat-window-root 四边渐隐 mask、liquidFlow /
259+
lightSweep 玻璃流光关键帧、以及 shell 的 ::before/::after 玻璃层、
260+
is-collapsing/is-expanding/is-minimized 全窗口几何复位,均随 full 形态一并
261+
退环境。compact 态的最小化/折叠/展开几何由 index.css 的 subtitle-web-host
262+
规则统一负责,这里不再注入 full 形态资源。 */
374263
/* 输入区提到光晕层之上,保持原始不透明度 */
375264
.composer-panel {
376265
position: relative !important;
@@ -659,7 +548,10 @@
659548
</div>
660549

661550
<!-- React Chat(与 index.html 完全相同的 DOM 结构)-->
662-
<div id="react-chat-window-overlay">
551+
<!-- overlay 默认 hidden(与 index.html 一致):在 React 挂载完成、shell 已带
552+
data-chat-surface-mode="compact" 之前不渲染任何东西,避免先闪一帧 full 形态。
553+
app-react-chat-window.js 的 openWindow() 会在 mountWindow() 之后置 hidden=false。 -->
554+
<div id="react-chat-window-overlay" hidden>
663555
<div id="react-chat-window-backdrop"></div>
664556
<div id="react-chat-window-shell" role="dialog" aria-modal="true" aria-labelledby="react-chat-window-title">
665557
<div id="react-chat-window-drag-handle" aria-hidden="true"></div>

tests/unit/test_react_chat_window_static.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -500,23 +500,31 @@ def test_desktop_compact_layout_change_resets_anchor_only_when_base_surface_chan
500500
assert "compactSurfaceAnchorSnapshot = '';" not in listener_block
501501

502502

503-
def test_electron_compact_chat_root_mask_does_not_clip_history_layer():
503+
def test_electron_compact_chat_retires_full_surface_chrome():
504504
template = CHAT_TEMPLATE_PATH.read_text(encoding="utf-8")
505505

506+
# The standalone /chat window renders the shared compact capsule (driven by
507+
# static/css/index.css's `body.subtitle-web-host #react-chat-window-shell
508+
# [data-chat-surface-mode="compact"]` rule set, which chat.html's
509+
# subtitle-web-host body opts into) instead of a bespoke full-window glass
510+
# panel. The retired full form used to paint an empty glass panel for one
511+
# frame before React mounted and collapsed it to compact ("先 full 再
512+
# compact" 的那一帧). chat.html must NOT re-introduce that full surface.
513+
#
514+
# Retired full-surface artifacts that must stay gone:
515+
assert "@keyframes liquidFlow" not in template # 玻璃流光关键帧
516+
assert "@keyframes lightSweep" not in template
517+
assert "-webkit-mask-image" not in template # 全窗口 root 四边渐隐 mask
518+
assert "#react-chat-window-shell:not(.is-minimized)::before" not in template
519+
assert "#react-chat-window-shell:not(.is-minimized)::after" not in template
520+
assert "inset: 40px 25px 25px 20px" not in template # 全窗口 shell 几何
521+
522+
# The shell font tweak survives (compact still uses #react-chat-window-root).
506523
assert "#react-chat-window-root {" in template
507-
assert (
508-
'body.electron-chat-window.subtitle-web-host '
509-
'#react-chat-window-shell[data-chat-surface-mode="compact"] #react-chat-window-root'
510-
) in template
511-
512-
compact_override_block = template.split(
513-
'body.electron-chat-window.subtitle-web-host '
514-
'#react-chat-window-shell[data-chat-surface-mode="compact"] #react-chat-window-root',
515-
1,
516-
)[1].split("@keyframes liquidFlow", 1)[0]
517-
518-
assert "-webkit-mask-image: none !important;" in compact_override_block
519-
assert "mask-image: none !important;" in compact_override_block
524+
# The overlay must start hidden so nothing paints before React mounts the
525+
# compact surface — parity with templates/index.html, which is what kills the
526+
# pre-mount full-form flash.
527+
assert 'id="react-chat-window-overlay" hidden' in template
520528

521529

522530
def test_compact_history_controls_collapse_gives_height_back_to_history_scroll():

0 commit comments

Comments
 (0)