@blade-hq/agent-react 2610.0.0-beta.70 → 2610.0.0-beta.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -5
- package/dist/{chunk-MAAMCOAU.js → chunk-IA6J2NTB.js} +4 -3
- package/dist/components/AgentLoopBlock.d.ts +2 -1
- package/dist/components/AskUserQuestionBlock.d.ts +3 -1
- package/dist/components/AssistantTurnBlock.d.ts +8 -4
- package/dist/components/ChatInput.d.ts +7 -1
- package/dist/components/ChatSurface.d.ts +105 -1
- package/dist/components/ChatView.d.ts +1 -1
- package/dist/components/MessageList.d.ts +13 -4
- package/dist/components/PlanUpdateBlock.d.ts +2 -1
- package/dist/components/PostChatFollowupBlock.d.ts +5 -1
- package/dist/components/ToolCallBlock.d.ts +6 -2
- package/dist/components/TurnNavRail.d.ts +23 -0
- package/dist/components/UserMessageBubble.d.ts +6 -2
- package/dist/embed/blade-chat-element.d.ts +4 -3
- package/dist/embed/entry.d.ts +2 -0
- package/dist/{highlighted-body-B3W2YXNL-IASCZDV2.js → highlighted-body-B3W2YXNL-YF4GVJGP.js} +2 -2
- package/dist/hooks/use-turn-navigation.d.ts +117 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +1911 -1176
- package/dist/index.js.map +1 -1
- package/dist/lib/utils.d.ts +15 -2
- package/dist/{mermaid-3ZIDBTTL-BPVVWTVV.js → mermaid-3ZIDBTTL-QL4YGD6I.js} +2 -2
- package/dist/style.css +488 -494
- package/dist/style.full.css +499 -498
- package/package.json +2 -2
- package/public-api.md +329 -4
- /package/dist/{chunk-MAAMCOAU.js.map → chunk-IA6J2NTB.js.map} +0 -0
- /package/dist/{highlighted-body-B3W2YXNL-IASCZDV2.js.map → highlighted-body-B3W2YXNL-YF4GVJGP.js.map} +0 -0
- /package/dist/{mermaid-3ZIDBTTL-BPVVWTVV.js.map → mermaid-3ZIDBTTL-QL4YGD6I.js.map} +0 -0
package/dist/style.css
CHANGED
|
@@ -1,11 +1,107 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* @blade-hq/agent-react 自包含样式。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* 这份文件只放 Tailwind 工具类表达不了的东西,其余视觉一律由组件上的 Tailwind
|
|
5
|
+
* class 定义一次(R1:一个视觉效果只在一处定义):
|
|
6
|
+
*
|
|
7
|
+
* - CSS 变量(主题、圆角、gutter)与 `:host` 尺寸默认值;
|
|
8
|
+
* - 容器查询(`@container`):按「容器宽度」而不是视口伸缩的内边距与断点;
|
|
9
|
+
* - Markdown 排版:正文是 streamdown 生成的 HTML,没有类名可挂,只能在这里写;
|
|
10
|
+
* - 无 Tailwind 预检时组件仍需要的少量 rest(按钮游标、textarea 去边框);
|
|
11
|
+
* - 跨元素的形状约束,如 `.blade-chat-messages-content > div` 的轮次间距。
|
|
12
|
+
*
|
|
13
|
+
* 组件上的 Tailwind class 不再需要在这里重复一份。视觉规则的层序见下面
|
|
14
|
+
* `@layer` 声明:兜底在 components 层,Tailwind 工具类在 utilities 层,
|
|
15
|
+
* 接入方无层的普通 CSS 天然最高优先——所以 `.blade-chat-user-bubble { background: red }`
|
|
16
|
+
* 一定生效,不需要 `!important`。
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/* ------------------------------------------------------------ 语义锚点清单
|
|
20
|
+
*
|
|
21
|
+
* 公开契约:每个可见区块的根元素固定带一个 blade-chat-* 类,接入方用普通 CSS
|
|
22
|
+
* 选它即可覆盖 SDK 默认样式(README「样式定制」第 4 层),不需要 !important,
|
|
23
|
+
* 也不需要跟着 SDK 的构建顺序走。
|
|
24
|
+
*
|
|
25
|
+
* 锚点只承担「可被选中」职责,不承载视觉规则。下面的兜底样式里出现的锚点,
|
|
26
|
+
* 只是恰好需要兜底的那几个;清单本身才是契约的一部分。
|
|
27
|
+
*
|
|
28
|
+
* scripts/gen-embed-styles.mjs 会校验这份清单的两件事:源码里出现的每个锚点都
|
|
29
|
+
* 必须在这里登记;清单里的每个锚点都必须出现在三份 CSS 产物中。新增可见区块时
|
|
30
|
+
* 先在这里登记锚点,再让元素带上它。
|
|
31
|
+
*
|
|
32
|
+
* @blade-chat-anchors
|
|
33
|
+
* blade-chat
|
|
34
|
+
* blade-chat-advanced
|
|
35
|
+
* blade-chat-agent-loop
|
|
36
|
+
* blade-chat-ask-card
|
|
37
|
+
* blade-chat-ask-option
|
|
38
|
+
* blade-chat-assistant-text
|
|
39
|
+
* blade-chat-assistant-turn
|
|
40
|
+
* blade-chat-banner
|
|
41
|
+
* blade-chat-codeblock
|
|
42
|
+
* blade-chat-codeblock-body
|
|
43
|
+
* blade-chat-codeblock-header
|
|
44
|
+
* blade-chat-context-card
|
|
45
|
+
* blade-chat-context-chevron
|
|
46
|
+
* blade-chat-context-copy
|
|
47
|
+
* blade-chat-context-detail
|
|
48
|
+
* blade-chat-context-group-items
|
|
49
|
+
* blade-chat-context-icon
|
|
50
|
+
* blade-chat-context-status
|
|
51
|
+
* blade-chat-context-summary
|
|
52
|
+
* blade-chat-context-title
|
|
53
|
+
* blade-chat-empty
|
|
54
|
+
* blade-chat-error-bar
|
|
55
|
+
* blade-chat-error-block
|
|
56
|
+
* blade-chat-error-row
|
|
57
|
+
* blade-chat-file-card
|
|
58
|
+
* blade-chat-file-card-icon
|
|
59
|
+
* blade-chat-file-card-name
|
|
60
|
+
* blade-chat-followup
|
|
61
|
+
* blade-chat-followup-action
|
|
62
|
+
* blade-chat-host
|
|
63
|
+
* blade-chat-input
|
|
64
|
+
* blade-chat-input-inner
|
|
65
|
+
* blade-chat-input-toolbar
|
|
66
|
+
* blade-chat-login
|
|
67
|
+
* blade-chat-markdown
|
|
68
|
+
* blade-chat-mcp-app
|
|
69
|
+
* blade-chat-memory-refs
|
|
70
|
+
* blade-chat-messages
|
|
71
|
+
* blade-chat-messages-content
|
|
72
|
+
* blade-chat-messages-scroll
|
|
73
|
+
* blade-chat-plan
|
|
74
|
+
* blade-chat-plan-block
|
|
75
|
+
* blade-chat-prose
|
|
76
|
+
* blade-chat-queue
|
|
77
|
+
* blade-chat-queue-item
|
|
78
|
+
* blade-chat-queue-notice
|
|
79
|
+
* blade-chat-render-error
|
|
80
|
+
* blade-chat-replay-bar
|
|
81
|
+
* blade-chat-scroll-bottom
|
|
82
|
+
* blade-chat-scroll-bottom-label
|
|
83
|
+
* blade-chat-textarea
|
|
84
|
+
* blade-chat-thinking
|
|
85
|
+
* blade-chat-tool-row
|
|
86
|
+
* blade-chat-user-bubble
|
|
87
|
+
* blade-chat-user-col
|
|
88
|
+
* blade-chat-user-row
|
|
7
89
|
*/
|
|
8
90
|
|
|
91
|
+
/* 层序先定死:兜底排在 Tailwind 工具类之前,换肤和覆盖才有稳定的先后。
|
|
92
|
+
* 三份产物都从这一行开始,Tailwind 自己那份声明用的是同一个顺序。
|
|
93
|
+
*
|
|
94
|
+
* properties 是 Tailwind 自己的 --tw-* 初始值层,必须排在最前:它的 `* { --tw-*: … }`
|
|
95
|
+
* 一旦排在 utilities 之后,就会把工具类设的 translate / ring / shadow 变量初始化掉。
|
|
96
|
+
*
|
|
97
|
+
* 最后一层 blade-chat-overrides 是给「必须压过组件自己 Tailwind 类」的规则用的:窄容器里
|
|
98
|
+
* 放宽用户消息宽度、iOS 聚焦不缩放、代码块与 Markdown 的排版——这些规则一旦
|
|
99
|
+
* 掉进 components 层就会被同元素的 utilities 盖掉,等于没写。接入方的普通
|
|
100
|
+
* CSS 不分层,仍然赢过这里所有层。 */
|
|
101
|
+
@layer properties, theme, base, components, utilities, blade-chat-overrides;
|
|
102
|
+
|
|
103
|
+
/* 变量不分层:它是主题契约,接入方在页面或祖先元素上重设同名变量即可换肤,
|
|
104
|
+
* 分层反而让"谁覆盖谁"取决于产物拼接顺序。 */
|
|
9
105
|
:root,
|
|
10
106
|
:host {
|
|
11
107
|
--background: 0 0% 100%;
|
|
@@ -54,588 +150,486 @@
|
|
|
54
150
|
--user-msg-border: 38 30% 19%;
|
|
55
151
|
}
|
|
56
152
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/* <blade-chat> 宿主默认块级 + 默认高度;页面对元素写的任何尺寸规则都会覆盖
|
|
60
|
-
* :host 默认值。host 容器把高度传导给内部 flex 链,消息区撑满、输入框钉底。 */
|
|
61
|
-
:host {
|
|
62
|
-
display: block;
|
|
63
|
-
height: 560px;
|
|
64
|
-
}
|
|
153
|
+
@layer components {
|
|
154
|
+
/* -------------------------------------------------------------- 布局骨架 */
|
|
65
155
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
156
|
+
/* <blade-chat> 宿主默认块级 + 默认高度;页面对元素写的任何尺寸规则都会覆盖
|
|
157
|
+
* :host 默认值。host 容器把高度传导给内部 flex 链,消息区撑满、输入框钉底。 */
|
|
158
|
+
:host {
|
|
159
|
+
display: block;
|
|
160
|
+
height: 560px;
|
|
161
|
+
}
|
|
71
162
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.blade-chat {
|
|
78
|
-
/* 具名容器:宿主或以后的子组件万一在中间又建了个匿名 query container,
|
|
79
|
-
* 下面的 @container 查询不会悄悄改成以那个为基准。 */
|
|
80
|
-
container: blade-chat / inline-size;
|
|
81
|
-
display: flex;
|
|
82
|
-
flex-direction: column;
|
|
83
|
-
flex: 1 1 0%;
|
|
84
|
-
min-height: 0;
|
|
85
|
-
min-width: 0;
|
|
86
|
-
overflow: hidden;
|
|
87
|
-
--blade-chat-gutter: 1rem;
|
|
88
|
-
--blade-chat-turn-gap: 1.5rem;
|
|
89
|
-
background: hsl(var(--background));
|
|
90
|
-
color: hsl(var(--foreground));
|
|
91
|
-
font-family:
|
|
92
|
-
system-ui,
|
|
93
|
-
-apple-system,
|
|
94
|
-
"Segoe UI",
|
|
95
|
-
Roboto,
|
|
96
|
-
"PingFang SC",
|
|
97
|
-
"Microsoft YaHei",
|
|
98
|
-
sans-serif;
|
|
99
|
-
}
|
|
163
|
+
.blade-chat-host {
|
|
164
|
+
height: 100%;
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
}
|
|
100
168
|
|
|
101
|
-
/*
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
169
|
+
/* 聊天根容器。SDK 常被嵌进只有 300-400px 宽的侧栏,而宿主页面视口是全宽的,
|
|
170
|
+
* 所以内边距一律按「容器宽度」伸缩,不能用视口断点——那会在窄容器里反向命中最大值。
|
|
171
|
+
* container-type 建在这里(而不是消息区),是为了让消息区和输入区共享同一个 cqi
|
|
172
|
+
* 基准,两者左右边缘才对得齐。代价是内部内容不再向外传递固有宽度,所以宿主需要给
|
|
173
|
+
* 容器一个确定宽度(flex/grid 拉伸或显式宽度都可以)。
|
|
174
|
+
* 底色与文字色也从这里给:根节点上没有对应的 Tailwind class。 */
|
|
106
175
|
.blade-chat {
|
|
107
|
-
|
|
108
|
-
|
|
176
|
+
/* 具名容器:宿主或以后的子组件万一在中间又建了个匿名 query container,
|
|
177
|
+
* 下面的 @container 查询不会悄悄改成以那个为基准。 */
|
|
178
|
+
container: blade-chat / inline-size;
|
|
179
|
+
min-width: 0;
|
|
180
|
+
--blade-chat-gutter: 1rem;
|
|
181
|
+
--blade-chat-turn-gap: 1.5rem;
|
|
182
|
+
background: hsl(var(--background));
|
|
183
|
+
color: hsl(var(--foreground));
|
|
184
|
+
font-family:
|
|
185
|
+
system-ui,
|
|
186
|
+
-apple-system,
|
|
187
|
+
"Segoe UI",
|
|
188
|
+
Roboto,
|
|
189
|
+
"PingFang SC",
|
|
190
|
+
"Microsoft YaHei",
|
|
191
|
+
sans-serif;
|
|
109
192
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.blade-chat-messages {
|
|
113
|
-
position: relative;
|
|
114
|
-
flex: 1 1 0%;
|
|
115
|
-
min-height: 0;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/* 滚动内容的内边距。这一层过去只有 Tailwind class,宿主没装 Tailwind 时消息完全贴边。 */
|
|
119
|
-
.blade-chat-messages-scroll {
|
|
120
|
-
padding: calc(var(--blade-chat-gutter) * 1.4) var(--blade-chat-gutter)
|
|
121
|
-
calc(var(--blade-chat-gutter) * 1.1 + var(--blade-chat-pin-spacer, 0px));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.blade-chat-messages-content {
|
|
125
|
-
margin: 0 auto;
|
|
126
|
-
max-width: 748px;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.blade-chat-messages-content > div {
|
|
130
|
-
display: flex;
|
|
131
|
-
flex-direction: column;
|
|
132
|
-
gap: var(--blade-chat-turn-gap);
|
|
133
|
-
min-width: 0;
|
|
134
|
-
}
|
|
135
193
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
color: hsl(var(--muted-foreground));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
.blade-chat-login,
|
|
149
|
-
.blade-chat-version-mismatch {
|
|
150
|
-
display: flex;
|
|
151
|
-
flex: 1 1 0%;
|
|
152
|
-
align-items: center;
|
|
153
|
-
justify-content: center;
|
|
154
|
-
padding: 1.5rem;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/* ---------------------------------------------------------------- 消息气泡 */
|
|
158
|
-
|
|
159
|
-
.blade-chat-user-row {
|
|
160
|
-
display: flex;
|
|
161
|
-
justify-content: flex-end;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
.blade-chat-user-col {
|
|
165
|
-
display: flex;
|
|
166
|
-
flex-direction: column;
|
|
167
|
-
align-items: flex-end;
|
|
168
|
-
gap: 0.75rem;
|
|
169
|
-
max-width: 72%;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/* 窄容器里 72% 只剩 250px 左右,一句话就折三行,这里放宽。
|
|
173
|
-
* 这类需要跳变而非连续伸缩的值才用 @container 查询。 */
|
|
174
|
-
@container blade-chat (max-width: 480px) {
|
|
175
|
-
.blade-chat-user-col {
|
|
176
|
-
max-width: 88%;
|
|
194
|
+
/* 上面两个变量的兜底值必须留在 @supports 外面。不能靠「同一个变量写两遍、让浏览器
|
|
195
|
+
* 丢掉无效的那条」降级:自定义属性在声明处不做类型校验,带 cqi 的值在旧浏览器里同样是
|
|
196
|
+
* 合法 token、照样覆盖兜底值,失效发生在 padding: var(...) 的使用处——结果是整条 padding
|
|
197
|
+
* 作废变成 0,而不是回落到兜底值。 */
|
|
198
|
+
@supports (container-type: inline-size) and (width: 1cqi) {
|
|
199
|
+
.blade-chat {
|
|
200
|
+
--blade-chat-gutter: clamp(0.875rem, 4cqi, 2.5rem);
|
|
201
|
+
--blade-chat-turn-gap: clamp(1.25rem, 3cqi, 2.25rem);
|
|
202
|
+
}
|
|
177
203
|
}
|
|
178
204
|
|
|
179
|
-
|
|
180
|
-
|
|
205
|
+
/* 滚动内容的内边距。左右按上面的 gutter 变量走,宿主没装 Tailwind 时消息也不会贴边;
|
|
206
|
+
* 底部那份补白是消息顶置功能的 spacer(--blade-chat-pin-spacer 由组件写行内变量)。 */
|
|
207
|
+
.blade-chat-messages-scroll {
|
|
208
|
+
padding: calc(var(--blade-chat-gutter) * 1.4) var(--blade-chat-gutter)
|
|
209
|
+
calc(var(--blade-chat-gutter) * 1.1 + var(--blade-chat-pin-spacer, 0px));
|
|
181
210
|
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
.blade-chat-user-bubble {
|
|
185
|
-
max-width: 100%;
|
|
186
|
-
border: 1px solid hsl(var(--user-msg-border));
|
|
187
|
-
background: hsl(var(--user-msg-bg));
|
|
188
|
-
color: hsl(var(--user-msg-fg));
|
|
189
|
-
border-radius: 20px;
|
|
190
|
-
border-bottom-right-radius: 6px;
|
|
191
|
-
padding: 13px 18px;
|
|
192
|
-
font-size: 0.875rem;
|
|
193
|
-
line-height: 1.65;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.blade-chat-assistant-turn {
|
|
197
|
-
display: flex;
|
|
198
|
-
flex-direction: column;
|
|
199
|
-
gap: 0.75rem;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
.blade-chat-assistant-text {
|
|
203
|
-
font-size: 15px;
|
|
204
|
-
line-height: 2;
|
|
205
|
-
color: hsl(var(--foreground));
|
|
206
|
-
}
|
|
207
211
|
|
|
208
|
-
.blade-chat
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.blade-chat-error-block {
|
|
214
|
-
max-width: 85%;
|
|
215
|
-
border-left: 3px solid hsl(var(--border));
|
|
216
|
-
padding: 0.25rem 1rem;
|
|
217
|
-
font-size: 0.875rem;
|
|
218
|
-
line-height: 1.75rem;
|
|
219
|
-
color: hsl(var(--muted-foreground));
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/* ------------------------------------------------------------- 背景信息卡片 */
|
|
212
|
+
/* 轮次之间的间距用容器宽度算(见 .blade-chat 的说明),挂在内层容器上。 */
|
|
213
|
+
.blade-chat-messages-content > div {
|
|
214
|
+
gap: var(--blade-chat-turn-gap);
|
|
215
|
+
}
|
|
223
216
|
|
|
224
|
-
.blade-chat-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
217
|
+
.blade-chat-empty {
|
|
218
|
+
display: flex;
|
|
219
|
+
flex-direction: column;
|
|
220
|
+
align-items: center;
|
|
221
|
+
justify-content: center;
|
|
222
|
+
gap: 0.75rem;
|
|
223
|
+
/* 这里的双写是有效降级:cqi 出现在属性值里,旧浏览器会丢掉整条声明并回落到上一条。 */
|
|
224
|
+
padding: 4rem 0;
|
|
225
|
+
padding: clamp(2.5rem, 12cqi, 6rem) 0;
|
|
226
|
+
color: hsl(var(--muted-foreground));
|
|
227
|
+
}
|
|
230
228
|
|
|
231
|
-
|
|
232
|
-
display: flex;
|
|
233
|
-
cursor: pointer;
|
|
234
|
-
list-style: none;
|
|
235
|
-
align-items: center;
|
|
236
|
-
gap: 0.5rem;
|
|
237
|
-
padding: 0.625rem 0.75rem;
|
|
238
|
-
}
|
|
229
|
+
/* -------------------------------------------------------------- 输入区 */
|
|
239
230
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
231
|
+
/* 左右内边距和消息区共用同一个 gutter,否则输入框与消息文字左边缘对不齐。
|
|
232
|
+
* 上下留白由组件上的 py-3 / pt-0 给。 */
|
|
233
|
+
.blade-chat-input {
|
|
234
|
+
/* 队列面板占位时组件会加上 border-t-0 收起这条线,所以这里不能写死:写死会
|
|
235
|
+
盖过那个切换。用变量保留默认值,外层仍按原样渲染一条分隔线。 */
|
|
236
|
+
border-top: var(--blade-chat-input-top-border, 1px solid hsl(var(--border)));
|
|
237
|
+
padding-left: var(--blade-chat-gutter);
|
|
238
|
+
padding-right: var(--blade-chat-gutter);
|
|
239
|
+
}
|
|
243
240
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
241
|
+
/* 队列面板的外层左右留白:必须跟下面输入框一致,两边各自居中才不会错位。
|
|
242
|
+
* 默认跟随本包输入框用的同一个 gutter 变量;宿主输入框用别的留白时(内置 Web
|
|
243
|
+
* 的输入框外层是 px-5),在自己的样式里覆盖 --blade-chat-queue-gutter 即可。 */
|
|
244
|
+
.blade-chat-queue {
|
|
245
|
+
--blade-chat-queue-gutter: var(--blade-chat-gutter, 1rem);
|
|
246
|
+
padding-left: var(--blade-chat-queue-gutter);
|
|
247
|
+
padding-right: var(--blade-chat-queue-gutter);
|
|
248
|
+
}
|
|
248
249
|
|
|
249
|
-
|
|
250
|
-
.blade-chat-context-status {
|
|
251
|
-
display: block;
|
|
252
|
-
}
|
|
250
|
+
/* ------------------------------------------------- 无 preflight 时的控件复位 */
|
|
253
251
|
|
|
254
|
-
.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
/* 组件上的工具类不负责这些:宿主只用 style.css 且自己的 Tailwind 关了 preflight 时,
|
|
253
|
+
输入框和按钮会退回浏览器默认外观(原生边框、原生按钮底色)。 */
|
|
254
|
+
.blade-chat-textarea {
|
|
255
|
+
border: 0;
|
|
256
|
+
font: inherit;
|
|
257
|
+
}
|
|
258
258
|
|
|
259
|
-
.blade-chat-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
259
|
+
.blade-chat-input-inner button,
|
|
260
|
+
.blade-chat-codeblock-header button,
|
|
261
|
+
.blade-chat-ask-card button {
|
|
262
|
+
cursor: pointer;
|
|
263
|
+
border: 0;
|
|
264
|
+
background-color: transparent;
|
|
265
|
+
}
|
|
266
266
|
|
|
267
|
-
/*
|
|
268
|
-
--motion-duration-fast / --motion-ease-enter 数值保持一致(这个包独立发布,
|
|
269
|
-
没有内部 app 的 CSS 变量可用,只能各自写字面量)。 */
|
|
270
|
-
.blade-chat-context-chevron {
|
|
271
|
-
transition: transform 180ms cubic-bezier(0.25, 0.1, 0.25, 1);
|
|
272
|
-
}
|
|
267
|
+
/* ------------------------------------------------------------ 出错条配色 */
|
|
273
268
|
|
|
274
|
-
/*
|
|
275
|
-
|
|
276
|
-
.blade-chat-
|
|
277
|
-
|
|
269
|
+
/* 配色由 .blade-chat-error-bar 的 --destructive 变量给,别写死 red-*:
|
|
270
|
+
* Tailwind 的 dark: 变体跟的是系统偏好,会和 data-theme 主题打架。 */
|
|
271
|
+
.blade-chat-error-bar {
|
|
272
|
+
border-bottom-color: hsl(var(--destructive) / 0.3);
|
|
273
|
+
background: hsl(var(--destructive) / 0.08);
|
|
274
|
+
color: hsl(var(--destructive));
|
|
275
|
+
}
|
|
278
276
|
}
|
|
279
277
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
278
|
+
@layer blade-chat-overrides {
|
|
279
|
+
/* ------------------------------------------------- 窄容器与移动端的手感 */
|
|
280
|
+
/* 需要跳变而非连续伸缩的值才用 @container:窄容器里 72% 只剩 250px 左右,
|
|
281
|
+
* 一句话就折三行。这条必须压过组件上的 max-w-[72%],所以归 blade-chat-overrides。 */
|
|
282
|
+
@container blade-chat (max-width: 480px) {
|
|
283
|
+
.blade-chat-user-col {
|
|
284
|
+
max-width: 88%;
|
|
285
|
+
}
|
|
287
286
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
gap: 0.375rem;
|
|
293
|
-
border-top: 1px solid hsl(var(--border));
|
|
294
|
-
padding: 0.5rem;
|
|
295
|
-
}
|
|
287
|
+
.blade-chat-scroll-bottom-label {
|
|
288
|
+
display: none;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
296
291
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
292
|
+
/* Keep embedded ChatView usable on iOS without forcing every host app to know
|
|
293
|
+
Safari's 16px focus-zoom threshold. Desktop sizing remains unchanged.
|
|
294
|
+
text-sm / text-xs 会让输入控件低于 16px,所以这条也归 blade-chat-overrides。 */
|
|
295
|
+
@media (hover: none) and (pointer: coarse) {
|
|
296
|
+
.blade-chat-textarea,
|
|
297
|
+
.blade-chat-ask-card input,
|
|
298
|
+
.blade-chat-ask-card textarea {
|
|
299
|
+
font-size: 1rem;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.blade-chat-input-inner button {
|
|
303
|
+
min-width: 44px;
|
|
304
|
+
min-height: 44px;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
307
|
|
|
308
|
-
/*
|
|
309
|
-
|
|
310
|
-
/* 左右内边距和消息区共用同一个 gutter,否则输入框与消息文字左边缘对不齐。 */
|
|
311
|
-
.blade-chat-input {
|
|
312
|
-
/* 队列面板占位时组件会加上 border-t-0 收起这条线,所以这里不能写死:写死会
|
|
313
|
-
盖过那个切换。用变量保留默认值,外层仍按原样渲染一条分隔线。 */
|
|
314
|
-
border-top: var(--blade-chat-input-top-border, 1px solid hsl(var(--border)));
|
|
315
|
-
/* 上下留白由组件上的 py-3 / pt-0 给:队列面板贴在它上方时要把上留白去掉,
|
|
316
|
-
写死在这里会盖掉那个切换(内置 Web 的输入框外层同样是 pt-0)。
|
|
317
|
-
左右留白仍走 gutter 变量,跟队列面板共用同一份。 */
|
|
318
|
-
padding-left: var(--blade-chat-gutter);
|
|
319
|
-
padding-right: var(--blade-chat-gutter);
|
|
320
|
-
}
|
|
308
|
+
/* ------------------------------------------------------------- Markdown */
|
|
321
309
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
max-width: 748px;
|
|
328
|
-
border: 1px solid hsl(var(--border));
|
|
329
|
-
background: hsl(var(--card));
|
|
330
|
-
/* 圆角由组件上的 rounded-2xl / rounded-b-2xl 给:队列面板贴在它上方时
|
|
331
|
-
上两角要变直角,写死在这里会盖掉那个切换。 */
|
|
332
|
-
padding: 0.5rem 0.75rem;
|
|
333
|
-
}
|
|
310
|
+
/* 正文是 streamdown 生成的 HTML,元素上没有类名可挂,排版只能写在这里。
|
|
311
|
+
* 反过来,带 Tailwind class 的那几个外壳(codeblock、prose 容器)不在这里重复。 */
|
|
312
|
+
.blade-chat-markdown {
|
|
313
|
+
min-width: 0;
|
|
314
|
+
}
|
|
334
315
|
|
|
335
|
-
/*
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
padding-right: var(--blade-chat-queue-gutter);
|
|
342
|
-
}
|
|
316
|
+
/* 窄容器里真正把版面撑破的是内容而不是内边距:宽表格、大图、超长 URL 都会把整个
|
|
317
|
+
* 消息区顶宽,然后出现一条横向滚动条。表格自己滚,图片自己缩,长 token 强制断行。 */
|
|
318
|
+
.blade-chat-markdown [data-streamdown="table-wrapper"] {
|
|
319
|
+
max-width: 100%;
|
|
320
|
+
min-width: 0;
|
|
321
|
+
}
|
|
343
322
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
font: inherit;
|
|
351
|
-
font-size: 0.875rem;
|
|
352
|
-
line-height: 1.5rem;
|
|
353
|
-
padding: 0.25rem 0;
|
|
354
|
-
min-height: 28px;
|
|
355
|
-
max-height: 12rem;
|
|
356
|
-
outline: none;
|
|
357
|
-
}
|
|
323
|
+
/* 横向滚动发生在 table 的父层。streamdown 用 Tailwind 的 overflow-x-auto 实现它,
|
|
324
|
+
* 宿主没装 Tailwind 时那个类是空的,所以这里用普通 CSS 兜住。 */
|
|
325
|
+
.blade-chat-markdown [data-streamdown="table-wrapper"] > div:last-child {
|
|
326
|
+
overflow-x: auto;
|
|
327
|
+
max-width: 100%;
|
|
328
|
+
}
|
|
358
329
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
.blade-chat-ask-card input,
|
|
364
|
-
.blade-chat-ask-card textarea {
|
|
365
|
-
font-size: 1rem;
|
|
330
|
+
.blade-chat-markdown img,
|
|
331
|
+
.blade-chat-markdown video {
|
|
332
|
+
max-width: 100%;
|
|
333
|
+
height: auto;
|
|
366
334
|
}
|
|
367
335
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
336
|
+
/* 长 URL 和长内联代码是撑宽的另外两个常见肇事者。用 anywhere 而不是 break-word:
|
|
337
|
+
* 只有 anywhere 参与 min-content 计算,break-word 挡不住 flex item 被顶宽。 */
|
|
338
|
+
.blade-chat-markdown :not(pre) > code,
|
|
339
|
+
.blade-chat-markdown a {
|
|
340
|
+
overflow-wrap: anywhere;
|
|
371
341
|
}
|
|
372
|
-
}
|
|
373
342
|
|
|
374
|
-
.blade-chat-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
343
|
+
.blade-chat-prose p {
|
|
344
|
+
margin: 0.5em 0;
|
|
345
|
+
}
|
|
378
346
|
|
|
379
|
-
|
|
347
|
+
.blade-chat-prose > p:first-child,
|
|
348
|
+
.blade-chat-prose > ul:first-child,
|
|
349
|
+
.blade-chat-prose > ol:first-child {
|
|
350
|
+
margin-top: 0;
|
|
351
|
+
}
|
|
380
352
|
|
|
381
|
-
.blade-chat-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
gap: 0.5rem;
|
|
387
|
-
vertical-align: middle;
|
|
388
|
-
}
|
|
353
|
+
.blade-chat-prose > p:last-child,
|
|
354
|
+
.blade-chat-prose > ul:last-child,
|
|
355
|
+
.blade-chat-prose > ol:last-child {
|
|
356
|
+
margin-bottom: 0;
|
|
357
|
+
}
|
|
389
358
|
|
|
390
|
-
.blade-chat-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
cursor: pointer;
|
|
396
|
-
border: 1px solid hsl(var(--border));
|
|
397
|
-
border-radius: 0.375rem;
|
|
398
|
-
background: hsl(var(--card));
|
|
399
|
-
color: hsl(var(--card-foreground));
|
|
400
|
-
padding: 0.375rem 0.625rem;
|
|
401
|
-
font-size: 0.75rem;
|
|
402
|
-
font-weight: 500;
|
|
403
|
-
line-height: 1.25rem;
|
|
404
|
-
text-align: left;
|
|
405
|
-
}
|
|
359
|
+
.blade-chat-prose ul,
|
|
360
|
+
.blade-chat-prose ol {
|
|
361
|
+
margin: 0.5em 0;
|
|
362
|
+
padding-left: 1.4em;
|
|
363
|
+
}
|
|
406
364
|
|
|
407
|
-
.blade-chat-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
365
|
+
.blade-chat-prose li {
|
|
366
|
+
margin: 0.25em 0;
|
|
367
|
+
}
|
|
411
368
|
|
|
412
|
-
.blade-chat-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
369
|
+
.blade-chat-prose h1 {
|
|
370
|
+
font-size: 1.25em;
|
|
371
|
+
font-weight: 600;
|
|
372
|
+
margin: 1em 0 0.5em;
|
|
373
|
+
}
|
|
416
374
|
|
|
417
|
-
.blade-chat-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
375
|
+
.blade-chat-prose h2 {
|
|
376
|
+
font-size: 1.15em;
|
|
377
|
+
font-weight: 600;
|
|
378
|
+
margin: 1em 0 0.5em;
|
|
379
|
+
}
|
|
422
380
|
|
|
423
|
-
|
|
424
|
-
.blade-chat-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
max-width: min(15rem, 60cqi);
|
|
430
|
-
}
|
|
381
|
+
.blade-chat-prose h3,
|
|
382
|
+
.blade-chat-prose h4 {
|
|
383
|
+
font-size: 1.05em;
|
|
384
|
+
font-weight: 600;
|
|
385
|
+
margin: 0.9em 0 0.4em;
|
|
386
|
+
}
|
|
431
387
|
|
|
432
|
-
.blade-chat-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
388
|
+
.blade-chat-prose blockquote {
|
|
389
|
+
border-left: 3px solid hsl(var(--border));
|
|
390
|
+
margin: 0.5em 0;
|
|
391
|
+
padding-left: 0.9em;
|
|
392
|
+
color: hsl(var(--muted-foreground));
|
|
393
|
+
}
|
|
436
394
|
|
|
437
|
-
.blade-chat-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}
|
|
395
|
+
.blade-chat-prose a {
|
|
396
|
+
color: hsl(var(--primary));
|
|
397
|
+
text-decoration: underline;
|
|
398
|
+
}
|
|
441
399
|
|
|
442
|
-
|
|
400
|
+
.blade-chat-prose code {
|
|
401
|
+
background: hsl(var(--muted) / 0.6);
|
|
402
|
+
border-radius: 0.25rem;
|
|
403
|
+
padding: 0.1em 0.35em;
|
|
404
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
405
|
+
font-size: 0.9em;
|
|
406
|
+
}
|
|
443
407
|
|
|
444
|
-
.blade-chat-
|
|
445
|
-
|
|
446
|
-
.
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
408
|
+
.blade-chat-prose table {
|
|
409
|
+
border-collapse: collapse;
|
|
410
|
+
margin: 0.75em 0;
|
|
411
|
+
width: 100%;
|
|
412
|
+
}
|
|
450
413
|
|
|
451
|
-
.blade-chat-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
458
|
-
font-size: 11px;
|
|
459
|
-
color: hsl(var(--foreground));
|
|
460
|
-
}
|
|
414
|
+
.blade-chat-prose th,
|
|
415
|
+
.blade-chat-prose td {
|
|
416
|
+
border: 1px solid hsl(var(--border));
|
|
417
|
+
padding: 0.4em 0.7em;
|
|
418
|
+
text-align: left;
|
|
419
|
+
}
|
|
461
420
|
|
|
462
|
-
/*
|
|
421
|
+
/* 代码块正文(<pre>)的排版:外层 codeblock 外壳与滚动由组件上的类给,
|
|
422
|
+
* 这里只补等宽字体和底色。 */
|
|
423
|
+
.blade-chat-codeblock-body {
|
|
424
|
+
background: hsl(var(--muted) / 0.25);
|
|
425
|
+
padding: 0.875rem 1rem;
|
|
426
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
427
|
+
font-size: 13.5px;
|
|
428
|
+
line-height: 1.7;
|
|
429
|
+
}
|
|
463
430
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
431
|
+
/* 代码块里的内联 code 不再套一层底色和留白。 */
|
|
432
|
+
.blade-chat-codeblock-body code {
|
|
433
|
+
background: transparent;
|
|
434
|
+
padding: 0;
|
|
435
|
+
}
|
|
468
436
|
|
|
469
|
-
/*
|
|
470
|
-
|
|
471
|
-
.blade-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
437
|
+
/* ---------------------------------------------------------------- 动效 */
|
|
438
|
+
|
|
439
|
+
.blade-shimmer-text {
|
|
440
|
+
background: linear-gradient(
|
|
441
|
+
90deg,
|
|
442
|
+
hsl(var(--muted-foreground)) 0%,
|
|
443
|
+
hsl(var(--foreground)) 50%,
|
|
444
|
+
hsl(var(--muted-foreground)) 100%
|
|
445
|
+
);
|
|
446
|
+
background-size: 200% 100%;
|
|
447
|
+
-webkit-background-clip: text;
|
|
448
|
+
background-clip: text;
|
|
449
|
+
-webkit-text-fill-color: transparent;
|
|
450
|
+
color: transparent;
|
|
451
|
+
animation: blade-shimmer 2s linear infinite;
|
|
452
|
+
}
|
|
475
453
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
454
|
+
@keyframes blade-shimmer {
|
|
455
|
+
from {
|
|
456
|
+
background-position: 200% 0;
|
|
457
|
+
}
|
|
458
|
+
to {
|
|
459
|
+
background-position: -200% 0;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
481
462
|
}
|
|
482
463
|
|
|
483
|
-
|
|
484
|
-
.blade-chat-markdown video {
|
|
485
|
-
max-width: 100%;
|
|
486
|
-
height: auto;
|
|
487
|
-
}
|
|
464
|
+
/* ------------------------------------------------------------ 消息导航轨 */
|
|
488
465
|
|
|
489
|
-
/*
|
|
490
|
-
*
|
|
491
|
-
.blade-
|
|
492
|
-
|
|
493
|
-
|
|
466
|
+
/* 右侧的发言刻度轨。定位绝对:悬停才展开的目录不能占布局宽度,否则同一行的
|
|
467
|
+
* 内容会被挤窄,而不悬停时那块空间永远是空的。 */
|
|
468
|
+
.blade-turn-nav {
|
|
469
|
+
position: absolute;
|
|
470
|
+
right: 0.5rem;
|
|
471
|
+
top: 50%;
|
|
472
|
+
transform: translateY(-50%);
|
|
473
|
+
z-index: 30;
|
|
494
474
|
}
|
|
495
475
|
|
|
496
|
-
.blade-
|
|
497
|
-
|
|
476
|
+
.blade-turn-nav-markers {
|
|
477
|
+
display: flex;
|
|
478
|
+
flex-direction: column;
|
|
479
|
+
align-items: flex-end;
|
|
480
|
+
max-height: 20rem;
|
|
481
|
+
/* 条数超过可视高度时要能滚:固定 hidden 会让后面的刻度永远点不到。
|
|
482
|
+
滚动条本身藏掉,它只是给长会话兜底。 */
|
|
483
|
+
overflow-y: auto;
|
|
484
|
+
scrollbar-width: none;
|
|
485
|
+
padding: 0.375rem 0.375rem 0.375rem 0;
|
|
486
|
+
-webkit-mask-image: linear-gradient(
|
|
487
|
+
to bottom,
|
|
488
|
+
transparent,
|
|
489
|
+
black 10%,
|
|
490
|
+
black 90%,
|
|
491
|
+
transparent
|
|
492
|
+
);
|
|
493
|
+
mask-image: linear-gradient(to bottom, transparent, black 10%, black 90%, transparent);
|
|
498
494
|
}
|
|
499
495
|
|
|
500
|
-
.blade-
|
|
501
|
-
|
|
502
|
-
.blade-chat-prose > ol:first-child {
|
|
503
|
-
margin-top: 0;
|
|
496
|
+
.blade-turn-nav-markers::-webkit-scrollbar {
|
|
497
|
+
display: none;
|
|
504
498
|
}
|
|
505
499
|
|
|
506
|
-
.blade-
|
|
507
|
-
|
|
508
|
-
.blade-chat-prose > ol:last-child {
|
|
509
|
-
margin-bottom: 0;
|
|
500
|
+
.blade-turn-nav-spacer-top {
|
|
501
|
+
margin-top: auto;
|
|
510
502
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
.blade-chat-prose ol {
|
|
514
|
-
margin: 0.5em 0;
|
|
515
|
-
padding-left: 1.4em;
|
|
503
|
+
.blade-turn-nav-spacer-bottom {
|
|
504
|
+
margin-bottom: auto;
|
|
516
505
|
}
|
|
517
506
|
|
|
518
|
-
.blade-
|
|
519
|
-
|
|
507
|
+
.blade-turn-nav-tick {
|
|
508
|
+
display: flex;
|
|
509
|
+
align-items: center;
|
|
510
|
+
height: 0.875rem;
|
|
511
|
+
flex-shrink: 0;
|
|
512
|
+
padding: 0;
|
|
513
|
+
border: 0;
|
|
514
|
+
background: none;
|
|
515
|
+
cursor: pointer;
|
|
520
516
|
}
|
|
521
517
|
|
|
522
|
-
.blade-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
518
|
+
.blade-turn-nav-tick > span {
|
|
519
|
+
display: block;
|
|
520
|
+
width: 0.75rem;
|
|
521
|
+
height: 0.125rem;
|
|
522
|
+
border-radius: 9999px;
|
|
523
|
+
background: hsl(var(--muted-foreground) / 0.35);
|
|
524
|
+
transition: width 0.15s ease, height 0.15s ease, background-color 0.15s ease;
|
|
526
525
|
}
|
|
527
526
|
|
|
528
|
-
.blade-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
527
|
+
.blade-turn-nav-tick[data-hovered="true"] > span {
|
|
528
|
+
width: 1.25rem;
|
|
529
|
+
height: 0.25rem;
|
|
530
|
+
background: hsl(var(--muted-foreground) / 0.7);
|
|
532
531
|
}
|
|
533
532
|
|
|
534
|
-
.blade-
|
|
535
|
-
.
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
margin: 0.9em 0 0.4em;
|
|
533
|
+
.blade-turn-nav-tick[data-active="true"] > span {
|
|
534
|
+
width: 1.25rem;
|
|
535
|
+
height: 0.25rem;
|
|
536
|
+
background: hsl(var(--foreground));
|
|
539
537
|
}
|
|
540
538
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
539
|
+
/* 定位的进度与失败提示:贴在刻度轨左侧,不随面板开合。 */
|
|
540
|
+
.blade-turn-nav-status {
|
|
541
|
+
position: absolute;
|
|
542
|
+
right: 100%;
|
|
543
|
+
top: 50%;
|
|
544
|
+
transform: translateY(-50%);
|
|
545
|
+
display: flex;
|
|
546
|
+
align-items: center;
|
|
547
|
+
gap: 0.5rem;
|
|
548
|
+
margin-right: 0.5rem;
|
|
549
|
+
padding: 0.25rem 0.625rem;
|
|
550
|
+
border: 1px solid hsl(var(--border));
|
|
551
|
+
border-radius: 9999px;
|
|
552
|
+
background: hsl(var(--popover));
|
|
553
|
+
color: hsl(var(--popover-foreground));
|
|
554
|
+
font-size: 0.75rem;
|
|
555
|
+
white-space: nowrap;
|
|
556
|
+
box-shadow: 0 4px 14px hsl(var(--foreground) / 0.12);
|
|
546
557
|
}
|
|
547
558
|
|
|
548
|
-
.blade-
|
|
559
|
+
.blade-turn-nav-status button {
|
|
560
|
+
border: 0;
|
|
561
|
+
background: none;
|
|
562
|
+
padding: 0;
|
|
549
563
|
color: hsl(var(--primary));
|
|
564
|
+
font-size: 0.75rem;
|
|
565
|
+
cursor: pointer;
|
|
550
566
|
text-decoration: underline;
|
|
551
567
|
}
|
|
552
568
|
|
|
553
|
-
.blade-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
569
|
+
.blade-turn-nav-panel {
|
|
570
|
+
position: absolute;
|
|
571
|
+
right: 100%;
|
|
572
|
+
/* 与刻度轨同心:顶对齐会让一个接近上限高度的面板整条往下长,聊天区是 overflow: hidden,
|
|
573
|
+
视口矮一点下面的条目就被裁掉、连滚都滚不到(滚动容器以为自己有完整高度)。 */
|
|
574
|
+
top: 50%;
|
|
575
|
+
transform: translateY(-50%);
|
|
576
|
+
padding-right: 0.5rem;
|
|
559
577
|
}
|
|
560
578
|
|
|
561
|
-
.blade-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
width:
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
.
|
|
579
|
+
.blade-turn-nav-list {
|
|
580
|
+
display: flex;
|
|
581
|
+
flex-direction: column;
|
|
582
|
+
width: 20rem;
|
|
583
|
+
/* 高度上限同时受视口约束,短视口里面板整体缩进去而不是被裁掉。 */
|
|
584
|
+
max-height: min(28rem, 60vh);
|
|
585
|
+
overflow-y: auto;
|
|
586
|
+
padding: 0.25rem 0;
|
|
569
587
|
border: 1px solid hsl(var(--border));
|
|
570
|
-
|
|
571
|
-
|
|
588
|
+
border-radius: 0.5rem;
|
|
589
|
+
background: hsl(var(--popover));
|
|
590
|
+
box-shadow: 0 10px 30px hsl(var(--foreground) / 0.18);
|
|
572
591
|
}
|
|
573
592
|
|
|
574
|
-
.blade-
|
|
575
|
-
|
|
593
|
+
.blade-turn-nav-item {
|
|
594
|
+
flex-shrink: 0;
|
|
595
|
+
padding: 0.375rem 0.75rem;
|
|
596
|
+
border: 0;
|
|
597
|
+
background: none;
|
|
598
|
+
text-align: left;
|
|
599
|
+
font-size: 0.75rem;
|
|
600
|
+
line-height: 1.25rem;
|
|
601
|
+
color: hsl(var(--popover-foreground));
|
|
602
|
+
white-space: nowrap;
|
|
576
603
|
overflow: hidden;
|
|
577
|
-
|
|
578
|
-
border-radius: 0.75rem;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
.blade-chat-codeblock-header {
|
|
582
|
-
display: flex;
|
|
583
|
-
align-items: center;
|
|
584
|
-
justify-content: space-between;
|
|
585
|
-
height: 34px;
|
|
586
|
-
border-bottom: 1px solid hsl(var(--border));
|
|
587
|
-
background: hsl(var(--muted) / 0.5);
|
|
588
|
-
padding: 0 0.375rem 0 0.875rem;
|
|
589
|
-
color: hsl(var(--muted-foreground));
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
.blade-chat-codeblock-header button {
|
|
604
|
+
text-overflow: ellipsis;
|
|
593
605
|
cursor: pointer;
|
|
594
|
-
border: 0;
|
|
595
|
-
background: transparent;
|
|
596
|
-
display: inline-flex;
|
|
597
|
-
align-items: center;
|
|
598
|
-
gap: 0.25rem;
|
|
599
|
-
color: inherit;
|
|
600
606
|
}
|
|
601
607
|
|
|
602
|
-
.blade-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
background: hsl(var(--muted) / 0.25);
|
|
606
|
-
padding: 0.875rem 1rem;
|
|
607
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
608
|
-
font-size: 13.5px;
|
|
609
|
-
line-height: 1.7;
|
|
608
|
+
.blade-turn-nav-item[data-hovered="true"],
|
|
609
|
+
.blade-turn-nav-item[data-active="true"] {
|
|
610
|
+
background: hsl(var(--accent));
|
|
610
611
|
}
|
|
611
612
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
613
|
+
/* 定位到某条发言后的短暂高亮。加到消息行本身(data-entry-id 那一层),
|
|
614
|
+
* 到点由 hook 摘掉类名,不改变滚动位置。内置 Web 的 app.css 有同名镜像。 */
|
|
615
|
+
.blade-turn-nav-flash {
|
|
616
|
+
animation: blade-turn-nav-flash 1.6s ease-out both;
|
|
617
|
+
border-radius: 0.5rem;
|
|
615
618
|
}
|
|
616
619
|
|
|
617
|
-
/*
|
|
618
|
-
|
|
619
|
-
.blade-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
hsl(var(--foreground)) 50%,
|
|
624
|
-
hsl(var(--muted-foreground)) 100%
|
|
625
|
-
);
|
|
626
|
-
background-size: 200% 100%;
|
|
627
|
-
-webkit-background-clip: text;
|
|
628
|
-
background-clip: text;
|
|
629
|
-
-webkit-text-fill-color: transparent;
|
|
630
|
-
color: transparent;
|
|
631
|
-
animation: blade-shimmer 2s linear infinite;
|
|
620
|
+
/* 减少动效:保留高亮但不动画,用户仍然看得见"定位到哪一条"。 */
|
|
621
|
+
@media (prefers-reduced-motion: reduce) {
|
|
622
|
+
.blade-turn-nav-flash {
|
|
623
|
+
animation: none;
|
|
624
|
+
background-color: hsl(var(--accent) / 0.75);
|
|
625
|
+
}
|
|
632
626
|
}
|
|
633
627
|
|
|
634
|
-
@keyframes blade-
|
|
628
|
+
@keyframes blade-turn-nav-flash {
|
|
635
629
|
from {
|
|
636
|
-
background-
|
|
630
|
+
background-color: hsl(var(--accent) / 0.75);
|
|
637
631
|
}
|
|
638
632
|
to {
|
|
639
|
-
background-
|
|
633
|
+
background-color: transparent;
|
|
640
634
|
}
|
|
641
635
|
}
|