@open-feishu-card/renderer 0.1.0 → 0.1.1

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/dist/styles.css CHANGED
@@ -1,605 +1,605 @@
1
- /**
2
- * open-feishu-card 样式表。
3
- * 精简复刻飞书 Universal Card 外观,自包含(不依赖飞书 design token)。
4
- * 类名沿用飞书原版前缀 universal-card。
5
- *
6
- * 注意:header 高光纹理图通过 JS 内联 base64 注入到 .universal-card-header__bg
7
- * 的 background-image(见 renderCard 输出的内联 style),故此处不写 url()。
8
- */
9
-
10
- .universal-card-root {
11
- /* 对齐飞书网页版 locale=zh 字体栈:西文优先 Helvetica Neue / Tahoma,
12
- * 中文再回落到 PingFang SC / Microsoft Yahei。原先把 PingFang 放在西文字体前,
13
- * Windows 上会用微软雅黑的拉丁字形,观感与真卡不一致。 */
14
- font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma,
15
- "PingFang SC", "Microsoft YaHei", Arial, "Hiragino Sans GB", sans-serif,
16
- "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
17
- font-size: 14px;
18
- line-height: 1.6;
19
- color: #1f2329;
20
- background-color: #fff;
21
- border-radius: 8px;
22
- border: 1px solid #dee0e3;
23
- overflow: hidden;
24
- width: 100%;
25
- max-width: 605px;
26
- box-sizing: border-box;
27
- box-shadow: 0 4px 14px rgba(31, 35, 41, 0.08);
28
- }
29
- .universal-card-root *,
30
- .universal-card-root *::before,
31
- .universal-card-root *::after { box-sizing: border-box; }
32
-
33
- /* ---- header ---- */
34
- .universal-card-header {
35
- width: 100%;
36
- overflow: hidden;
37
- border-top-left-radius: 8px;
38
- border-top-right-radius: 8px;
39
- }
40
- .universal-card-header__bg {
41
- box-sizing: border-box;
42
- width: 100%;
43
- padding: 12px;
44
- background-repeat: no-repeat;
45
- background-position: 0 0;
46
- /* 图宽=header宽,使纹理自身的左右暗边落在 header 两端、亮带居中 */
47
- background-size: 100% 140px;
48
- }
49
- /* 内容行:左侧图标 + 右侧标题区(对齐网页版 header__content = row) */
50
- .universal-card-header__content {
51
- width: 100%;
52
- display: flex;
53
- flex-direction: row;
54
- align-items: flex-start;
55
- }
56
- .universal-card-header__icon {
57
- display: flex;
58
- height: 24px;
59
- align-items: center;
60
- margin-right: 8px;
61
- flex-shrink: 0;
62
- color: inherit;
63
- }
64
- .universal-card-header__text {
65
- flex: 1;
66
- max-width: 100%;
67
- line-height: 24px;
68
- overflow: hidden;
69
- min-width: 0;
70
- }
71
- /* 标题行:标题 + 右侧标签同排 */
72
- .universal-card-header__text-title-wrapper,
73
- .universal-card-header__title-row {
74
- display: flex;
75
- flex-wrap: wrap;
76
- align-items: center;
77
- }
78
- .universal-card-header__tags {
79
- display: inline-flex;
80
- align-items: center;
81
- gap: 4px;
82
- line-height: 1;
83
- max-width: 100%;
84
- }
85
- .universal-card-header__text-title {
86
- overflow: hidden;
87
- margin-right: 4px;
88
- font-size: 16px;
89
- font-weight: 600;
90
- line-height: 24px;
91
- word-break: break-word;
92
- }
93
- /* 副标题:与标题同色,仅字重更轻(对齐真机 font-weight:400,无 opacity) */
94
- .universal-card-header__text-subtitle {
95
- margin-top: 2px;
96
- font-size: 14px;
97
- font-weight: 400;
98
- line-height: 22px;
99
- overflow: hidden;
100
- display: -webkit-box;
101
- -webkit-box-orient: vertical;
102
- -webkit-line-clamp: 1;
103
- word-break: break-word;
104
- }
105
-
106
- /* ---- body ---- */
107
- .universal-card-body {
108
- padding: 12px;
109
- display: flex;
110
- flex-direction: column;
111
- row-gap: 8px;
112
- align-items: flex-start;
113
- }
114
- .universal-card-body > * { width: 100%; box-sizing: border-box; }
115
-
116
- /* ---- markdown 段落 ---- */
117
- /* 对齐网页版:line-height 默认 1.6;具体字号/行高由组件内联 style 按 text_size 给出 */
118
- .universal-card-markdown {
119
- display: flex;
120
- width: 100%;
121
- box-sizing: border-box;
122
- font-size: 14px;
123
- line-height: 1.6;
124
- color: #1f2329;
125
- word-break: break-word;
126
- vertical-align: middle;
127
- }
128
- .universal-card-markdown__children {
129
- flex: 1;
130
- min-width: 0;
131
- overflow: hidden;
132
- white-space: pre-wrap;
133
- }
134
-
135
- /* ---- hr 分割线 ---- */
136
- .universal-card-hr {
137
- width: 100%;
138
- height: 1px;
139
- background-color: #dee0e3;
140
- border: none;
141
- margin: 8px 0;
142
- }
143
-
144
- /* ---- div ---- */
145
- .universal-card-div > * + * { margin-top: 8px; }
146
- /* div 带前置图标:icon 在左、文本在右排成一行(复刻网页版 .universal-card-div 布局) */
147
- .universal-card-div--with-icon {
148
- display: flex; flex-wrap: nowrap; align-items: flex-start; line-height: 1.6;
149
- }
150
- .universal-card-div--with-icon > * + * { margin-top: 0; }
151
- .universal-card-div__icon_wrapper {
152
- margin-right: 8px; flex-shrink: 0; height: 1.6em;
153
- display: flex; align-items: center; overflow: hidden;
154
- }
155
- .universal-card-div__content { flex: 1; min-width: 0; }
156
-
157
- /* ---- 布局:column_set / column ---- */
158
- .universal-card-column-set { display: flex; }
159
- .universal-card-column { box-sizing: border-box; overflow-wrap: anywhere; }
160
- /* 列内纵向间距唯一来源是 column 组件输出的 flex row-gap(默认 8px,可被 vertical_spacing 覆盖)。
161
- 这里不再给相邻子元素设 margin-top——否则与 row-gap 叠加,间距翻倍。 */
162
-
163
- /* ---- 图片 ---- */
164
- .universal-card-image__wrapper { display: flex; max-width: 100%; }
165
- .universal-card-image__host { max-width: 100%; height: auto; object-fit: cover; border-radius: 4px; }
166
- .universal-card-image__placeholder {
167
- display: inline-flex; align-items: center; justify-content: center;
168
- min-width: 80px; min-height: 48px; padding: 8px 12px;
169
- color: #8f959e; background: #f5f6f7; border: 1px dashed #dee0e3; border-radius: 4px;
170
- font-size: 12px;
171
- }
172
-
173
- /* ---- 按钮 ---- */
174
- /* 飞书按钮文本是纯文本、单行:min-height 容纳偶发换行,文字超长省略号收尾。
175
- 样式全集逆向自网页版 ud__button:三大族——outlined(描边)/ text(纯文字)/ filled(实心),
176
- 每族再分 default / primary / danger 色,另加 laser 渐变。默认(未加变体类)= outlined-default。 */
177
- .universal-card-button {
178
- display: inline-flex; align-items: center; justify-content: center;
179
- gap: 4px;
180
- min-height: 28px; padding: 4px 12px;
181
- font-size: 14px; line-height: 22px; border-radius: 6px;
182
- border: 1px solid transparent; background: transparent; color: #1f2329;
183
- cursor: pointer; text-decoration: none; box-sizing: border-box;
184
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
185
- transition: background-color .1s, border-color .1s, color .1s;
186
- }
187
- /* 按钮前置图标:继承按钮文字色(currentColor),高度对齐行高 */
188
- .universal-card-button__icon {
189
- display: inline-flex; align-items: center; justify-content: center;
190
- flex-shrink: 0; height: 1.2em; color: inherit;
191
- }
192
- .universal-card-button__icon .universal-card-icon { color: inherit; }
193
- /* default 宽度:按内容收缩。列是 flex column(默认 align-items:stretch),
194
- body 又有 > * { width:100% },不加这两条会被撑满所在列。 */
195
- .universal-card-button:not(.universal-card-button--block) {
196
- width: auto;
197
- max-width: 100%;
198
- align-self: flex-start;
199
- }
200
- /* fill(width:"fill"):撑满所在列 */
201
- .universal-card-button--block { width: 100%; }
202
-
203
- /* —— outlined 描边族 —— */
204
- /* default:灰描边 + 白底 + 深字(未加变体类的裸 .universal-card-button 已是白底深字,
205
- 这里补上默认灰边与 default 变体一致) */
206
- .universal-card-button,
207
- .universal-card-button--default {
208
- border-color: #dee0e3; background: #fff; color: #1f2329;
209
- }
210
- .universal-card-button--default:not(.universal-card-button--static):hover { background: #f5f6f7; }
211
- /* primary:蓝描边 + 蓝字 + 白底 */
212
- .universal-card-button--primary {
213
- border-color: #1456f0; background: #fff; color: #1456f0;
214
- }
215
- .universal-card-button--primary:not(.universal-card-button--static):hover { background: #f0f4ff; }
216
- /* danger:红描边 + 红字 + 白底 */
217
- .universal-card-button--danger {
218
- border-color: #f54a45; background: #fff; color: #f54a45;
219
- }
220
- .universal-card-button--danger:not(.universal-card-button--static):hover { background: #fef0f0; }
221
-
222
- /* —— text 纯文字族(无边框/无底色,按内容宽) —— */
223
- .universal-card-button--text,
224
- .universal-card-button--primary_text,
225
- .universal-card-button--danger_text {
226
- border-color: transparent; background: transparent; padding: 4px 8px;
227
- }
228
- .universal-card-button--text { color: #1f2329; }
229
- .universal-card-button--primary_text { color: #1456f0; }
230
- .universal-card-button--danger_text { color: #f54a45; }
231
- .universal-card-button--text:not(.universal-card-button--static):hover { background: #f5f6f7; }
232
- .universal-card-button--primary_text:not(.universal-card-button--static):hover { background: #f0f4ff; }
233
- .universal-card-button--danger_text:not(.universal-card-button--static):hover { background: #fef0f0; }
234
-
235
- /* —— filled 实心族(有底色 + 白字) —— */
236
- .universal-card-button--primary_filled {
237
- border-color: #1456f0; background: #1456f0; color: #fff;
238
- }
239
- .universal-card-button--primary_filled:not(.universal-card-button--static):hover { background: #0442d2; border-color: #0442d2; }
240
- .universal-card-button--danger_filled {
241
- border-color: #f54a45; background: #f54a45; color: #fff;
242
- }
243
- .universal-card-button--danger_filled:not(.universal-card-button--static):hover { background: #e22e28; border-color: #e22e28; }
244
- /* laser:飞书「激光」渐变实心按钮(蓝→紫渐变 + 白字) */
245
- .universal-card-button--laser {
246
- border-color: transparent; color: #fff;
247
- background: linear-gradient(97deg, #4e83fd 0%, #7a35f0 100%);
248
- }
249
- .universal-card-button--laser:not(.universal-card-button--static):hover { filter: brightness(1.05); }
250
-
251
- .universal-card-button--disabled,
252
- .universal-card-button:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
253
- /* 非跳转按钮:保留外观,但不可点(默认光标、无 hover、不响应点击) */
254
- .universal-card-button--static { cursor: default; pointer-events: none; }
255
-
256
- /* ---- 表单(预览:仅透传,无表单语义) ---- */
257
- .universal-card-form { display: flex; flex-direction: column; row-gap: 8px; }
258
- .universal-card-form > * { width: 100%; }
259
- /* input / select 等输入控件:预览里渲染成只读静态框,展示 placeholder */
260
- .universal-card-input--static {
261
- min-height: 32px; padding: 6px 12px; box-sizing: border-box;
262
- font-size: 14px; line-height: 20px; color: #8f959e;
263
- background: #f5f6f7; border: 1px solid #dee0e3; border-radius: 6px;
264
- cursor: default; pointer-events: none;
265
- }
266
-
267
- /* ---- action 容器 ---- */
268
- .universal-card-action { display: flex; flex-wrap: wrap; gap: 12px; }
269
-
270
- /* ---- checker 勾选器(对齐网页版 universal-card-checker) ---- */
271
- .universal-card-checker {
272
- display: flex; box-sizing: border-box; overflow: hidden; align-items: flex-start;
273
- color: inherit;
274
- }
275
- .universal-card-checker--hover.universal-card-checker:hover {
276
- background-color: rgba(31, 35, 41, 0.05); cursor: pointer;
277
- }
278
- .universal-card-checker--disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
279
- .universal-card-checker__checkbox-container {
280
- display: inline-flex; align-items: center; margin-right: 8px; flex-shrink: 0;
281
- height: calc(var(--universal-card-checker-line-height, 22px));
282
- position: relative; cursor: pointer;
283
- }
284
- /* 原生 checkbox 藏起,用自定义方框画外观;点击由外层 label / 本 label 承接 */
285
- .universal-card-checker__input {
286
- position: absolute; opacity: 0; width: 0; height: 0; margin: 0; padding: 0;
287
- }
288
- .universal-card-checker__box {
289
- width: 16px; height: 16px; box-sizing: border-box;
290
- border: 1px solid #8f959e; border-radius: 4px; background: #fff;
291
- display: inline-flex; align-items: center; justify-content: center;
292
- flex-shrink: 0; transition: background-color .1s, border-color .1s;
293
- }
294
- .universal-card-checker__input:checked + .universal-card-checker__box {
295
- background: #1456f0; border-color: #1456f0;
296
- }
297
- .universal-card-checker__input:checked + .universal-card-checker__box::after {
298
- content: ""; width: 3.5px; height: 7px;
299
- border: solid #fff; border-width: 0 2px 2px 0;
300
- transform: rotate(45deg) translateY(-0.5px);
301
- }
302
- .universal-card-checker__content {
303
- /* 真机:content 是 flex,唯一子项是 .universal-card-text(行内排版)。
304
- * 不要把 text_tag / plain_text 直接做成 flex 子项——行首空格会被吃掉,
305
- * tag 与后续文字贴死(真机靠 break-spaces + 行内流保留 content 里的空格)。 */
306
- display: flex; flex: 1; min-width: 35px;
307
- line-height: calc(var(--universal-card-checker-line-height, 22px));
308
- word-break: break-word;
309
- }
310
- /* 真机 .universal-card-text:保留连续空格(text_tag 后常见两个空格) */
311
- .universal-card-text {
312
- word-break: break-word;
313
- white-space: break-spaces;
314
- }
315
- /* 勾选态:删除线 / 透明度由 :has(:checked) 驱动,本地切换无需 JS */
316
- .universal-card-checker--strike:has(.universal-card-checker__input:checked) .universal-card-checker__content {
317
- text-decoration-line: line-through;
318
- text-decoration-color: inherit;
319
- }
320
- .universal-card-checker:has(.universal-card-checker__input:checked) .universal-card-checker__content {
321
- opacity: var(--checker-checked-opacity, 1);
322
- }
323
- .universal-card-checker__content--right { justify-content: right; }
324
- .universal-card-checker__content--center { justify-content: center; }
325
- .universal-card-checker__buttons {
326
- display: flex; margin-left: 16px; column-gap: 10px; max-width: 150px; flex-shrink: 0;
327
- align-items: center;
328
- }
329
- .universal-card-checker__buttons--auto-hide { opacity: 0; }
330
- .universal-card-checker:hover .universal-card-checker__buttons--auto-hide { opacity: 1; }
331
- .universal-card-checker__button { display: inline-flex; align-items: center; }
332
-
333
-
334
- /* ---- interactive_container 可点击交互容器 ---- */
335
- .universal-card-interactive-container {
336
- display: flex; flex-direction: column; box-sizing: border-box;
337
- border-radius: 6px; padding: 0; text-decoration: none; color: inherit;
338
- cursor: pointer; transition: background-color .1s;
339
- }
340
- .universal-card-interactive-container:not(.universal-card-interactive-container--disabled):hover {
341
- background-color: rgba(31, 35, 41, 0.05);
342
- }
343
- .universal-card-interactive-container--bordered { border: 1px solid #dee0e3; }
344
- /* disabled:去掉手型指针与 hover 灰底,外观退回普通块 */
345
- .universal-card-interactive-container--disabled {
346
- cursor: default; transition: none;
347
- }
348
-
349
- /* ---- collapsible_panel 折叠面板(原生 <details>/<summary>,纯 CSS 可点) ---- */
350
- /* 外层 <details> 容器:border/background/radius 由内联 style 给(来自 border/background_color)。 */
351
- .universal-card-collapsible-panel {
352
- box-sizing: border-box; overflow: hidden;
353
- }
354
- /* header(<summary>):可点击整行;去掉浏览器默认三角标记,标题占满、箭头贴右
355
- (icon_position=left 时靠 DOM 顺序在左)。 */
356
- .universal-card-collapsible-panel__header {
357
- display: flex; align-items: center; gap: 8px;
358
- padding: 8px 12px;
359
- cursor: pointer; box-sizing: border-box;
360
- list-style: none; user-select: none;
361
- }
362
- .universal-card-collapsible-panel__header::-webkit-details-marker { display: none; }
363
- .universal-card-collapsible-panel__header::marker { content: ''; }
364
- .universal-card-collapsible-panel__title {
365
- flex: 1; min-width: 0; font-size: 14px; line-height: 22px; color: #1f2329;
366
- word-break: break-word;
367
- }
368
- /* 箭头图标包裹:收起态角度 0;展开态(details[open])旋转到 --panel-icon-angle(内联给出,默认 -180deg)。
369
- 由用户点击 <summary> 切换 [open],箭头方向随之自动更新,无需 JS。 */
370
- .universal-card-collapsible-panel__icon {
371
- flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
372
- transition: transform .2s; color: #646a73; transform: rotate(0deg);
373
- }
374
- .universal-card-collapsible-panel[open] .universal-card-collapsible-panel__icon {
375
- transform: rotate(var(--panel-icon-angle, -180deg));
376
- }
377
- /* 内容区:展开时显示(折叠态由 <details> 交给浏览器隐藏)。左右/底部内边距对齐 header
378
- (真机内容 margin 0 12px 12px),顶部紧贴 header 不留空。 */
379
- .universal-card-collapsible-panel__content {
380
- box-sizing: border-box; padding: 0 12px 12px;
381
- }
382
-
383
- /* ---- 人员 person_v1 / person_list(对齐网页版 universal-card-person*)---- */
384
- .universal-card-person {
385
- display: inline-flex; align-items: center; width: auto; max-width: 100%;
386
- vertical-align: bottom;
387
- }
388
- .universal-card-person__content {
389
- display: flex; align-items: center; max-width: 100%; cursor: default;
390
- }
391
- /* 真机 --udtoken-tag-neutral-bg-normal = rgba(N900-raw, .1) = rgba(31,35,41,.1) */
392
- .universal-card-person__content--capsule.universal-card-person__content--name {
393
- background: rgba(31, 35, 41, 0.1); border-radius: 99px;
394
- }
395
- .universal-card-person__avatar-wrapper {
396
- display: flex; flex-shrink: 0;
397
- }
398
- .universal-card-person__internal-avatar,
399
- .universal-card-person-list__avatar,
400
- .universal-card-person-list__unknown-avatar {
401
- flex-shrink: 0; border-radius: 50%; object-fit: cover;
402
- display: inline-flex; align-items: center; justify-content: center;
403
- overflow: hidden; vertical-align: middle;
404
- }
405
- .universal-card-person__avatar--placeholder {
406
- background-color: #bbbfc4; color: #fff; font-weight: 500;
407
- line-height: 1; text-transform: uppercase; user-select: none;
408
- }
409
- .universal-card-person__name {
410
- display: inline-flex; align-items: center; min-width: 0;
411
- color: #1f2329; max-width: 100%;
412
- }
413
- .universal-card-person__name .universal-card-text--line-1 {
414
- display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;
415
- overflow: hidden; word-break: break-all;
416
- }
417
- .universal-card-person .universal-card-text { line-height: inherit; }
418
-
419
- .universal-card-person-list {
420
- display: flex; width: 100%; position: relative; align-items: flex-start;
421
- justify-content: flex-start;
422
- }
423
- .universal-card-person-list--table {
424
- flex-wrap: wrap; gap: 4px 8px; width: auto;
425
- }
426
- .universal-card-person-list__icon {
427
- margin-right: 8px; flex-shrink: 0; overflow: hidden;
428
- display: flex; align-items: center; height: 1.6em;
429
- }
430
- .universal-card-person-list__content {
431
- overflow: hidden; min-width: 0; flex: 1;
432
- }
433
- .universal-card-person-list__content--lines {
434
- display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden;
435
- }
436
- .universal-card-person-list__content--combine {
437
- display: flex; flex-wrap: wrap; column-gap: 12px; row-gap: 8px;
438
- }
439
- .universal-card-person-list__avatar-name {
440
- display: inline-flex; overflow: hidden; text-overflow: ellipsis;
441
- white-space: nowrap; align-items: center; max-width: 100%;
442
- }
443
- .universal-card-person-list__avatar-name .universal-card-person-list__avatar,
444
- .universal-card-person-list__avatar-name .universal-card-person-list__unknown-avatar {
445
- margin-right: 4px; flex-shrink: 0;
446
- }
447
- .universal-card-person-list__reaction-user {
448
- align-items: center; display: inline-flex; overflow: hidden;
449
- text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
450
- vertical-align: middle;
451
- }
452
- .universal-card-person-list__reaction-user--blue { color: #1456f0; }
453
- .universal-card-person-list__reaction-user--disabled { cursor: default; }
454
- .universal-card-person-list__reaction-user__name {
455
- overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
456
- vertical-align: middle; display: inline-block; max-width: 100%;
457
- }
458
- .universal-card-person-list__reaction-user__comma {
459
- color: #8f959e; white-space: pre; vertical-align: middle;
460
- }
461
- /* 葫芦串:叠放头像,重叠处用 SVG mask 挖月牙(对齐 ud__avatar-hollow-out,不用白描边) */
462
- .universal-card-person-list__avatar-group {
463
- display: inline-flex; align-items: center; white-space: nowrap;
464
- }
465
- .universal-card-person-list__avatar-group-item {
466
- display: inline-flex; border-radius: 50%; overflow: hidden;
467
- position: relative; flex-shrink: 0;
468
- }
469
- .universal-card-person-list__avatar-group-item .universal-card-person-list__avatar,
470
- .universal-card-person-list__avatar-group-item .universal-card-person-list__unknown-avatar {
471
- display: block; width: 100%; height: 100%;
472
- }
473
-
474
- /* ---- @人 / 链接 ---- */
475
- .universal-card-markdown-at { word-break: break-word; }
476
- .universal-card-markdown-link { color: #1456f0; text-decoration: none; }
477
- .universal-card-markdown-link:hover { text-decoration: underline; }
478
-
479
- /* ---- text_tag 彩色标签 ---- */
480
- .universal-card-text-tag { vertical-align: middle; margin: 0 2px; white-space: nowrap; }
481
-
482
- /* ---- markdown: heading / blockquote / list / code ---- */
483
- .universal-card-markdown-heading { word-break: break-word; }
484
- .universal-card-blockquote {
485
- padding-left: 10px; position: relative; color: #646a73;
486
- }
487
- .universal-card-blockquote::before {
488
- content: " "; position: absolute; left: 0; top: 0; height: 100%; width: 2px;
489
- background-color: #dee0e3;
490
- }
491
- .universal-card-markdown-list { text-align: left; }
492
- .universal-card-markdown-list__item { align-items: flex-start; }
493
- .universal-card-markdown-list__marker { color: #1456f0; line-height: 1.6; }
494
- .universal-card-markdown-list__li-content { display: inline-block; }
495
- .universal-card-code-span {
496
- border-radius: 4px; border: 1px solid #dee0e3; padding: 0 4px;
497
- background-color: #f5f6f7; font-family: Menlo, Consolas, monospace; font-size: 13px;
498
- }
499
- .universal-card-markdown-code-block {
500
- text-align: left; padding: 12px; min-width: 210px; margin: 4px 0;
501
- font-size: 13px; font-weight: 400; line-height: 1.5;
502
- background-color: #f5f6f7; border-radius: 6px; overflow-x: auto;
503
- font-family: Menlo, Consolas, monospace; white-space: pre;
504
- }
505
- .universal-card-emoji { display: inline; }
506
- /* emoji 雪碧图:<i> 的 background-image/size/position/width 由 emoji.css(larkw-emoji__img--emoji-*)提供;
507
- 这里只管行内对齐(vertical-align 让表情与文字基线大致对齐)。 */
508
- .universal-card-emoji__img { display: inline-block; vertical-align: -0.15em; }
509
-
510
- /* 图标(standard_icon / ud_icon):glyph 由图标字体 :before 画出。
511
- 字体 @font-face 与每图标 content 规则随 JS 注入(浏览器端 renderCard 自动注入,
512
- Node/SSR 端引入 open-feishu-card/icon-font.css)。这里只管布局对齐。 */
513
- .universal-card-icon {
514
- display: inline-flex;
515
- align-items: center;
516
- justify-content: center;
517
- vertical-align: -0.125em;
518
- }
519
-
520
- /* ---- chart 图表 ---- */
521
- /* 挂载容器:aspect-ratio / height 由内联 style 给(来自 aspect_ratio)。
522
- VChart 水合后会往 __vchart 里塞 <canvas>;水合前显示 loading 占位。 */
523
- .universal-card-chart {
524
- position: relative;
525
- width: 100%;
526
- box-sizing: border-box;
527
- overflow: hidden;
528
- }
529
- .universal-card-chart__vchart {
530
- position: relative;
531
- width: 100%;
532
- height: 100%;
533
- display: block;
534
- }
535
- .universal-card-chart__vchart canvas { display: block; }
536
- .universal-card-chart__loading,
537
- .universal-card-chart__placeholder {
538
- display: flex; align-items: center; justify-content: center;
539
- width: 100%; height: 100%;
540
- color: #8f959e; font-size: 12px;
541
- background: #f5f6f7; border: 1px dashed #dee0e3; border-radius: 4px;
542
- box-sizing: border-box;
543
- }
544
-
545
- /* ---- table 表格 ---- */
546
- .universal-card-table {
547
- width: 100%;
548
- box-sizing: border-box;
549
- border: 1px solid #dee0e3;
550
- border-radius: 6px;
551
- overflow: hidden;
552
- }
553
- .universal-card-table__scroll { width: 100%; overflow-x: auto; }
554
- .universal-card-table__table {
555
- width: 100%;
556
- border-collapse: collapse;
557
- table-layout: auto;
558
- font-size: 14px;
559
- color: #1f2329;
560
- }
561
- .universal-card-table__th,
562
- .universal-card-table__td {
563
- padding: 8px 12px;
564
- border-bottom: 1px solid #dee0e3;
565
- border-right: 1px solid #eff0f1;
566
- vertical-align: middle;
567
- box-sizing: border-box;
568
- }
569
- .universal-card-table__th:last-child,
570
- .universal-card-table__td:last-child { border-right: none; }
571
- .universal-card-table__tbody tr:last-child .universal-card-table__td { border-bottom: none; }
572
- .universal-card-table__th {
573
- font-size: 14px;
574
- line-height: 22px;
575
- white-space: nowrap;
576
- color: #1f2329;
577
- }
578
- .universal-card-table__th-text--bold { font-weight: 600; }
579
- .universal-card-table__cell {
580
- display: flex;
581
- align-items: center;
582
- gap: 4px;
583
- word-break: break-word;
584
- }
585
- .universal-card-table__tags { display: inline-flex; flex-wrap: wrap; gap: 4px; align-items: center; }
586
-
587
- /* 暗色主题下的表格/图表占位 */
588
- .universal-card-root.theme-dark .universal-card-table { border-color: #2e2e30; }
589
- .universal-card-root.theme-dark .universal-card-table__th,
590
- .universal-card-root.theme-dark .universal-card-table__td { border-color: #2e2e30; color: #d6d6d6; }
591
- .universal-card-root.theme-dark .universal-card-table__th { color: #ebebeb; }
592
- .universal-card-root.theme-dark .universal-card-chart__loading,
593
- .universal-card-root.theme-dark .universal-card-chart__placeholder {
594
- background: #232323; border-color: #2e2e30; color: #8a8a8a;
595
- }
596
-
597
- /* ---- 暗色主题(可选):给 .universal-card-root 加 .theme-dark 即可 ----
598
- 暗色高光图同样由 JS 注入;如需纯 CSS 暗色,可自行覆盖 background-image。 */
599
- .universal-card-root.theme-dark {
600
- color: #ebebeb;
601
- background-color: #1a1a1a;
602
- border-color: #2e2e30;
603
- }
604
- .universal-card-root.theme-dark .universal-card-markdown { color: #d6d6d6; }
605
- .universal-card-root.theme-dark .universal-card-hr { background-color: #2e2e30; }
1
+ /**
2
+ * open-feishu-card 样式表。
3
+ * 精简复刻飞书 Universal Card 外观,自包含(不依赖飞书 design token)。
4
+ * 类名沿用飞书原版前缀 universal-card。
5
+ *
6
+ * 注意:header 高光纹理图通过 JS 内联 base64 注入到 .universal-card-header__bg
7
+ * 的 background-image(见 renderCard 输出的内联 style),故此处不写 url()。
8
+ */
9
+
10
+ .universal-card-root {
11
+ /* 对齐飞书网页版 locale=zh 字体栈:西文优先 Helvetica Neue / Tahoma,
12
+ * 中文再回落到 PingFang SC / Microsoft Yahei。原先把 PingFang 放在西文字体前,
13
+ * Windows 上会用微软雅黑的拉丁字形,观感与真卡不一致。 */
14
+ font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma,
15
+ "PingFang SC", "Microsoft YaHei", Arial, "Hiragino Sans GB", sans-serif,
16
+ "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
17
+ font-size: 14px;
18
+ line-height: 1.6;
19
+ color: #1f2329;
20
+ background-color: #fff;
21
+ border-radius: 8px;
22
+ border: 1px solid #dee0e3;
23
+ overflow: hidden;
24
+ width: 100%;
25
+ max-width: 605px;
26
+ box-sizing: border-box;
27
+ box-shadow: 0 4px 14px rgba(31, 35, 41, 0.08);
28
+ }
29
+ .universal-card-root *,
30
+ .universal-card-root *::before,
31
+ .universal-card-root *::after { box-sizing: border-box; }
32
+
33
+ /* ---- header ---- */
34
+ .universal-card-header {
35
+ width: 100%;
36
+ overflow: hidden;
37
+ border-top-left-radius: 8px;
38
+ border-top-right-radius: 8px;
39
+ }
40
+ .universal-card-header__bg {
41
+ box-sizing: border-box;
42
+ width: 100%;
43
+ padding: 12px;
44
+ background-repeat: no-repeat;
45
+ background-position: 0 0;
46
+ /* 图宽=header宽,使纹理自身的左右暗边落在 header 两端、亮带居中 */
47
+ background-size: 100% 140px;
48
+ }
49
+ /* 内容行:左侧图标 + 右侧标题区(对齐网页版 header__content = row) */
50
+ .universal-card-header__content {
51
+ width: 100%;
52
+ display: flex;
53
+ flex-direction: row;
54
+ align-items: flex-start;
55
+ }
56
+ .universal-card-header__icon {
57
+ display: flex;
58
+ height: 24px;
59
+ align-items: center;
60
+ margin-right: 8px;
61
+ flex-shrink: 0;
62
+ color: inherit;
63
+ }
64
+ .universal-card-header__text {
65
+ flex: 1;
66
+ max-width: 100%;
67
+ line-height: 24px;
68
+ overflow: hidden;
69
+ min-width: 0;
70
+ }
71
+ /* 标题行:标题 + 右侧标签同排 */
72
+ .universal-card-header__text-title-wrapper,
73
+ .universal-card-header__title-row {
74
+ display: flex;
75
+ flex-wrap: wrap;
76
+ align-items: center;
77
+ }
78
+ .universal-card-header__tags {
79
+ display: inline-flex;
80
+ align-items: center;
81
+ gap: 4px;
82
+ line-height: 1;
83
+ max-width: 100%;
84
+ }
85
+ .universal-card-header__text-title {
86
+ overflow: hidden;
87
+ margin-right: 4px;
88
+ font-size: 16px;
89
+ font-weight: 600;
90
+ line-height: 24px;
91
+ word-break: break-word;
92
+ }
93
+ /* 副标题:与标题同色,仅字重更轻(对齐真机 font-weight:400,无 opacity) */
94
+ .universal-card-header__text-subtitle {
95
+ margin-top: 2px;
96
+ font-size: 14px;
97
+ font-weight: 400;
98
+ line-height: 22px;
99
+ overflow: hidden;
100
+ display: -webkit-box;
101
+ -webkit-box-orient: vertical;
102
+ -webkit-line-clamp: 1;
103
+ word-break: break-word;
104
+ }
105
+
106
+ /* ---- body ---- */
107
+ .universal-card-body {
108
+ padding: 12px;
109
+ display: flex;
110
+ flex-direction: column;
111
+ row-gap: 8px;
112
+ align-items: flex-start;
113
+ }
114
+ .universal-card-body > * { width: 100%; box-sizing: border-box; }
115
+
116
+ /* ---- markdown 段落 ---- */
117
+ /* 对齐网页版:line-height 默认 1.6;具体字号/行高由组件内联 style 按 text_size 给出 */
118
+ .universal-card-markdown {
119
+ display: flex;
120
+ width: 100%;
121
+ box-sizing: border-box;
122
+ font-size: 14px;
123
+ line-height: 1.6;
124
+ color: #1f2329;
125
+ word-break: break-word;
126
+ vertical-align: middle;
127
+ }
128
+ .universal-card-markdown__children {
129
+ flex: 1;
130
+ min-width: 0;
131
+ overflow: hidden;
132
+ white-space: pre-wrap;
133
+ }
134
+
135
+ /* ---- hr 分割线 ---- */
136
+ .universal-card-hr {
137
+ width: 100%;
138
+ height: 1px;
139
+ background-color: #dee0e3;
140
+ border: none;
141
+ margin: 8px 0;
142
+ }
143
+
144
+ /* ---- div ---- */
145
+ .universal-card-div > * + * { margin-top: 8px; }
146
+ /* div 带前置图标:icon 在左、文本在右排成一行(复刻网页版 .universal-card-div 布局) */
147
+ .universal-card-div--with-icon {
148
+ display: flex; flex-wrap: nowrap; align-items: flex-start; line-height: 1.6;
149
+ }
150
+ .universal-card-div--with-icon > * + * { margin-top: 0; }
151
+ .universal-card-div__icon_wrapper {
152
+ margin-right: 8px; flex-shrink: 0; height: 1.6em;
153
+ display: flex; align-items: center; overflow: hidden;
154
+ }
155
+ .universal-card-div__content { flex: 1; min-width: 0; }
156
+
157
+ /* ---- 布局:column_set / column ---- */
158
+ .universal-card-column-set { display: flex; }
159
+ .universal-card-column { box-sizing: border-box; overflow-wrap: anywhere; }
160
+ /* 列内纵向间距唯一来源是 column 组件输出的 flex row-gap(默认 8px,可被 vertical_spacing 覆盖)。
161
+ 这里不再给相邻子元素设 margin-top——否则与 row-gap 叠加,间距翻倍。 */
162
+
163
+ /* ---- 图片 ---- */
164
+ .universal-card-image__wrapper { display: flex; max-width: 100%; }
165
+ .universal-card-image__host { max-width: 100%; height: auto; object-fit: cover; border-radius: 4px; }
166
+ .universal-card-image__placeholder {
167
+ display: inline-flex; align-items: center; justify-content: center;
168
+ min-width: 80px; min-height: 48px; padding: 8px 12px;
169
+ color: #8f959e; background: #f5f6f7; border: 1px dashed #dee0e3; border-radius: 4px;
170
+ font-size: 12px;
171
+ }
172
+
173
+ /* ---- 按钮 ---- */
174
+ /* 飞书按钮文本是纯文本、单行:min-height 容纳偶发换行,文字超长省略号收尾。
175
+ 样式全集逆向自网页版 ud__button:三大族——outlined(描边)/ text(纯文字)/ filled(实心),
176
+ 每族再分 default / primary / danger 色,另加 laser 渐变。默认(未加变体类)= outlined-default。 */
177
+ .universal-card-button {
178
+ display: inline-flex; align-items: center; justify-content: center;
179
+ gap: 4px;
180
+ min-height: 28px; padding: 4px 12px;
181
+ font-size: 14px; line-height: 22px; border-radius: 6px;
182
+ border: 1px solid transparent; background: transparent; color: #1f2329;
183
+ cursor: pointer; text-decoration: none; box-sizing: border-box;
184
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
185
+ transition: background-color .1s, border-color .1s, color .1s;
186
+ }
187
+ /* 按钮前置图标:继承按钮文字色(currentColor),高度对齐行高 */
188
+ .universal-card-button__icon {
189
+ display: inline-flex; align-items: center; justify-content: center;
190
+ flex-shrink: 0; height: 1.2em; color: inherit;
191
+ }
192
+ .universal-card-button__icon .universal-card-icon { color: inherit; }
193
+ /* default 宽度:按内容收缩。列是 flex column(默认 align-items:stretch),
194
+ body 又有 > * { width:100% },不加这两条会被撑满所在列。 */
195
+ .universal-card-button:not(.universal-card-button--block) {
196
+ width: auto;
197
+ max-width: 100%;
198
+ align-self: flex-start;
199
+ }
200
+ /* fill(width:"fill"):撑满所在列 */
201
+ .universal-card-button--block { width: 100%; }
202
+
203
+ /* —— outlined 描边族 —— */
204
+ /* default:灰描边 + 白底 + 深字(未加变体类的裸 .universal-card-button 已是白底深字,
205
+ 这里补上默认灰边与 default 变体一致) */
206
+ .universal-card-button,
207
+ .universal-card-button--default {
208
+ border-color: #dee0e3; background: #fff; color: #1f2329;
209
+ }
210
+ .universal-card-button--default:not(.universal-card-button--static):hover { background: #f5f6f7; }
211
+ /* primary:蓝描边 + 蓝字 + 白底 */
212
+ .universal-card-button--primary {
213
+ border-color: #1456f0; background: #fff; color: #1456f0;
214
+ }
215
+ .universal-card-button--primary:not(.universal-card-button--static):hover { background: #f0f4ff; }
216
+ /* danger:红描边 + 红字 + 白底 */
217
+ .universal-card-button--danger {
218
+ border-color: #f54a45; background: #fff; color: #f54a45;
219
+ }
220
+ .universal-card-button--danger:not(.universal-card-button--static):hover { background: #fef0f0; }
221
+
222
+ /* —— text 纯文字族(无边框/无底色,按内容宽) —— */
223
+ .universal-card-button--text,
224
+ .universal-card-button--primary_text,
225
+ .universal-card-button--danger_text {
226
+ border-color: transparent; background: transparent; padding: 4px 8px;
227
+ }
228
+ .universal-card-button--text { color: #1f2329; }
229
+ .universal-card-button--primary_text { color: #1456f0; }
230
+ .universal-card-button--danger_text { color: #f54a45; }
231
+ .universal-card-button--text:not(.universal-card-button--static):hover { background: #f5f6f7; }
232
+ .universal-card-button--primary_text:not(.universal-card-button--static):hover { background: #f0f4ff; }
233
+ .universal-card-button--danger_text:not(.universal-card-button--static):hover { background: #fef0f0; }
234
+
235
+ /* —— filled 实心族(有底色 + 白字) —— */
236
+ .universal-card-button--primary_filled {
237
+ border-color: #1456f0; background: #1456f0; color: #fff;
238
+ }
239
+ .universal-card-button--primary_filled:not(.universal-card-button--static):hover { background: #0442d2; border-color: #0442d2; }
240
+ .universal-card-button--danger_filled {
241
+ border-color: #f54a45; background: #f54a45; color: #fff;
242
+ }
243
+ .universal-card-button--danger_filled:not(.universal-card-button--static):hover { background: #e22e28; border-color: #e22e28; }
244
+ /* laser:飞书「激光」渐变实心按钮(蓝→紫渐变 + 白字) */
245
+ .universal-card-button--laser {
246
+ border-color: transparent; color: #fff;
247
+ background: linear-gradient(97deg, #4e83fd 0%, #7a35f0 100%);
248
+ }
249
+ .universal-card-button--laser:not(.universal-card-button--static):hover { filter: brightness(1.05); }
250
+
251
+ .universal-card-button--disabled,
252
+ .universal-card-button:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
253
+ /* 非跳转按钮:保留外观,但不可点(默认光标、无 hover、不响应点击) */
254
+ .universal-card-button--static { cursor: default; pointer-events: none; }
255
+
256
+ /* ---- 表单(预览:仅透传,无表单语义) ---- */
257
+ .universal-card-form { display: flex; flex-direction: column; row-gap: 8px; }
258
+ .universal-card-form > * { width: 100%; }
259
+ /* input / select 等输入控件:预览里渲染成只读静态框,展示 placeholder */
260
+ .universal-card-input--static {
261
+ min-height: 32px; padding: 6px 12px; box-sizing: border-box;
262
+ font-size: 14px; line-height: 20px; color: #8f959e;
263
+ background: #f5f6f7; border: 1px solid #dee0e3; border-radius: 6px;
264
+ cursor: default; pointer-events: none;
265
+ }
266
+
267
+ /* ---- action 容器 ---- */
268
+ .universal-card-action { display: flex; flex-wrap: wrap; gap: 12px; }
269
+
270
+ /* ---- checker 勾选器(对齐网页版 universal-card-checker) ---- */
271
+ .universal-card-checker {
272
+ display: flex; box-sizing: border-box; overflow: hidden; align-items: flex-start;
273
+ color: inherit;
274
+ }
275
+ .universal-card-checker--hover.universal-card-checker:hover {
276
+ background-color: rgba(31, 35, 41, 0.05); cursor: pointer;
277
+ }
278
+ .universal-card-checker--disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
279
+ .universal-card-checker__checkbox-container {
280
+ display: inline-flex; align-items: center; margin-right: 8px; flex-shrink: 0;
281
+ height: calc(var(--universal-card-checker-line-height, 22px));
282
+ position: relative; cursor: pointer;
283
+ }
284
+ /* 原生 checkbox 藏起,用自定义方框画外观;点击由外层 label / 本 label 承接 */
285
+ .universal-card-checker__input {
286
+ position: absolute; opacity: 0; width: 0; height: 0; margin: 0; padding: 0;
287
+ }
288
+ .universal-card-checker__box {
289
+ width: 16px; height: 16px; box-sizing: border-box;
290
+ border: 1px solid #8f959e; border-radius: 4px; background: #fff;
291
+ display: inline-flex; align-items: center; justify-content: center;
292
+ flex-shrink: 0; transition: background-color .1s, border-color .1s;
293
+ }
294
+ .universal-card-checker__input:checked + .universal-card-checker__box {
295
+ background: #1456f0; border-color: #1456f0;
296
+ }
297
+ .universal-card-checker__input:checked + .universal-card-checker__box::after {
298
+ content: ""; width: 3.5px; height: 7px;
299
+ border: solid #fff; border-width: 0 2px 2px 0;
300
+ transform: rotate(45deg) translateY(-0.5px);
301
+ }
302
+ .universal-card-checker__content {
303
+ /* 真机:content 是 flex,唯一子项是 .universal-card-text(行内排版)。
304
+ * 不要把 text_tag / plain_text 直接做成 flex 子项——行首空格会被吃掉,
305
+ * tag 与后续文字贴死(真机靠 break-spaces + 行内流保留 content 里的空格)。 */
306
+ display: flex; flex: 1; min-width: 35px;
307
+ line-height: calc(var(--universal-card-checker-line-height, 22px));
308
+ word-break: break-word;
309
+ }
310
+ /* 真机 .universal-card-text:保留连续空格(text_tag 后常见两个空格) */
311
+ .universal-card-text {
312
+ word-break: break-word;
313
+ white-space: break-spaces;
314
+ }
315
+ /* 勾选态:删除线 / 透明度由 :has(:checked) 驱动,本地切换无需 JS */
316
+ .universal-card-checker--strike:has(.universal-card-checker__input:checked) .universal-card-checker__content {
317
+ text-decoration-line: line-through;
318
+ text-decoration-color: inherit;
319
+ }
320
+ .universal-card-checker:has(.universal-card-checker__input:checked) .universal-card-checker__content {
321
+ opacity: var(--checker-checked-opacity, 1);
322
+ }
323
+ .universal-card-checker__content--right { justify-content: right; }
324
+ .universal-card-checker__content--center { justify-content: center; }
325
+ .universal-card-checker__buttons {
326
+ display: flex; margin-left: 16px; column-gap: 10px; max-width: 150px; flex-shrink: 0;
327
+ align-items: center;
328
+ }
329
+ .universal-card-checker__buttons--auto-hide { opacity: 0; }
330
+ .universal-card-checker:hover .universal-card-checker__buttons--auto-hide { opacity: 1; }
331
+ .universal-card-checker__button { display: inline-flex; align-items: center; }
332
+
333
+
334
+ /* ---- interactive_container 可点击交互容器 ---- */
335
+ .universal-card-interactive-container {
336
+ display: flex; flex-direction: column; box-sizing: border-box;
337
+ border-radius: 6px; padding: 0; text-decoration: none; color: inherit;
338
+ cursor: pointer; transition: background-color .1s;
339
+ }
340
+ .universal-card-interactive-container:not(.universal-card-interactive-container--disabled):hover {
341
+ background-color: rgba(31, 35, 41, 0.05);
342
+ }
343
+ .universal-card-interactive-container--bordered { border: 1px solid #dee0e3; }
344
+ /* disabled:去掉手型指针与 hover 灰底,外观退回普通块 */
345
+ .universal-card-interactive-container--disabled {
346
+ cursor: default; transition: none;
347
+ }
348
+
349
+ /* ---- collapsible_panel 折叠面板(原生 <details>/<summary>,纯 CSS 可点) ---- */
350
+ /* 外层 <details> 容器:border/background/radius 由内联 style 给(来自 border/background_color)。 */
351
+ .universal-card-collapsible-panel {
352
+ box-sizing: border-box; overflow: hidden;
353
+ }
354
+ /* header(<summary>):可点击整行;去掉浏览器默认三角标记,标题占满、箭头贴右
355
+ (icon_position=left 时靠 DOM 顺序在左)。 */
356
+ .universal-card-collapsible-panel__header {
357
+ display: flex; align-items: center; gap: 8px;
358
+ padding: 8px 12px;
359
+ cursor: pointer; box-sizing: border-box;
360
+ list-style: none; user-select: none;
361
+ }
362
+ .universal-card-collapsible-panel__header::-webkit-details-marker { display: none; }
363
+ .universal-card-collapsible-panel__header::marker { content: ''; }
364
+ .universal-card-collapsible-panel__title {
365
+ flex: 1; min-width: 0; font-size: 14px; line-height: 22px; color: #1f2329;
366
+ word-break: break-word;
367
+ }
368
+ /* 箭头图标包裹:收起态角度 0;展开态(details[open])旋转到 --panel-icon-angle(内联给出,默认 -180deg)。
369
+ 由用户点击 <summary> 切换 [open],箭头方向随之自动更新,无需 JS。 */
370
+ .universal-card-collapsible-panel__icon {
371
+ flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
372
+ transition: transform .2s; color: #646a73; transform: rotate(0deg);
373
+ }
374
+ .universal-card-collapsible-panel[open] .universal-card-collapsible-panel__icon {
375
+ transform: rotate(var(--panel-icon-angle, -180deg));
376
+ }
377
+ /* 内容区:展开时显示(折叠态由 <details> 交给浏览器隐藏)。左右/底部内边距对齐 header
378
+ (真机内容 margin 0 12px 12px),顶部紧贴 header 不留空。 */
379
+ .universal-card-collapsible-panel__content {
380
+ box-sizing: border-box; padding: 0 12px 12px;
381
+ }
382
+
383
+ /* ---- 人员 person_v1 / person_list(对齐网页版 universal-card-person*)---- */
384
+ .universal-card-person {
385
+ display: inline-flex; align-items: center; width: auto; max-width: 100%;
386
+ vertical-align: bottom;
387
+ }
388
+ .universal-card-person__content {
389
+ display: flex; align-items: center; max-width: 100%; cursor: default;
390
+ }
391
+ /* 真机 --udtoken-tag-neutral-bg-normal = rgba(N900-raw, .1) = rgba(31,35,41,.1) */
392
+ .universal-card-person__content--capsule.universal-card-person__content--name {
393
+ background: rgba(31, 35, 41, 0.1); border-radius: 99px;
394
+ }
395
+ .universal-card-person__avatar-wrapper {
396
+ display: flex; flex-shrink: 0;
397
+ }
398
+ .universal-card-person__internal-avatar,
399
+ .universal-card-person-list__avatar,
400
+ .universal-card-person-list__unknown-avatar {
401
+ flex-shrink: 0; border-radius: 50%; object-fit: cover;
402
+ display: inline-flex; align-items: center; justify-content: center;
403
+ overflow: hidden; vertical-align: middle;
404
+ }
405
+ .universal-card-person__avatar--placeholder {
406
+ background-color: #bbbfc4; color: #fff; font-weight: 500;
407
+ line-height: 1; text-transform: uppercase; user-select: none;
408
+ }
409
+ .universal-card-person__name {
410
+ display: inline-flex; align-items: center; min-width: 0;
411
+ color: #1f2329; max-width: 100%;
412
+ }
413
+ .universal-card-person__name .universal-card-text--line-1 {
414
+ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;
415
+ overflow: hidden; word-break: break-all;
416
+ }
417
+ .universal-card-person .universal-card-text { line-height: inherit; }
418
+
419
+ .universal-card-person-list {
420
+ display: flex; width: 100%; position: relative; align-items: flex-start;
421
+ justify-content: flex-start;
422
+ }
423
+ .universal-card-person-list--table {
424
+ flex-wrap: wrap; gap: 4px 8px; width: auto;
425
+ }
426
+ .universal-card-person-list__icon {
427
+ margin-right: 8px; flex-shrink: 0; overflow: hidden;
428
+ display: flex; align-items: center; height: 1.6em;
429
+ }
430
+ .universal-card-person-list__content {
431
+ overflow: hidden; min-width: 0; flex: 1;
432
+ }
433
+ .universal-card-person-list__content--lines {
434
+ display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden;
435
+ }
436
+ .universal-card-person-list__content--combine {
437
+ display: flex; flex-wrap: wrap; column-gap: 12px; row-gap: 8px;
438
+ }
439
+ .universal-card-person-list__avatar-name {
440
+ display: inline-flex; overflow: hidden; text-overflow: ellipsis;
441
+ white-space: nowrap; align-items: center; max-width: 100%;
442
+ }
443
+ .universal-card-person-list__avatar-name .universal-card-person-list__avatar,
444
+ .universal-card-person-list__avatar-name .universal-card-person-list__unknown-avatar {
445
+ margin-right: 4px; flex-shrink: 0;
446
+ }
447
+ .universal-card-person-list__reaction-user {
448
+ align-items: center; display: inline-flex; overflow: hidden;
449
+ text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
450
+ vertical-align: middle;
451
+ }
452
+ .universal-card-person-list__reaction-user--blue { color: #1456f0; }
453
+ .universal-card-person-list__reaction-user--disabled { cursor: default; }
454
+ .universal-card-person-list__reaction-user__name {
455
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
456
+ vertical-align: middle; display: inline-block; max-width: 100%;
457
+ }
458
+ .universal-card-person-list__reaction-user__comma {
459
+ color: #8f959e; white-space: pre; vertical-align: middle;
460
+ }
461
+ /* 葫芦串:叠放头像,重叠处用 SVG mask 挖月牙(对齐 ud__avatar-hollow-out,不用白描边) */
462
+ .universal-card-person-list__avatar-group {
463
+ display: inline-flex; align-items: center; white-space: nowrap;
464
+ }
465
+ .universal-card-person-list__avatar-group-item {
466
+ display: inline-flex; border-radius: 50%; overflow: hidden;
467
+ position: relative; flex-shrink: 0;
468
+ }
469
+ .universal-card-person-list__avatar-group-item .universal-card-person-list__avatar,
470
+ .universal-card-person-list__avatar-group-item .universal-card-person-list__unknown-avatar {
471
+ display: block; width: 100%; height: 100%;
472
+ }
473
+
474
+ /* ---- @人 / 链接 ---- */
475
+ .universal-card-markdown-at { word-break: break-word; }
476
+ .universal-card-markdown-link { color: #1456f0; text-decoration: none; }
477
+ .universal-card-markdown-link:hover { text-decoration: underline; }
478
+
479
+ /* ---- text_tag 彩色标签 ---- */
480
+ .universal-card-text-tag { vertical-align: middle; margin: 0 2px; white-space: nowrap; }
481
+
482
+ /* ---- markdown: heading / blockquote / list / code ---- */
483
+ .universal-card-markdown-heading { word-break: break-word; }
484
+ .universal-card-blockquote {
485
+ padding-left: 10px; position: relative; color: #646a73;
486
+ }
487
+ .universal-card-blockquote::before {
488
+ content: " "; position: absolute; left: 0; top: 0; height: 100%; width: 2px;
489
+ background-color: #dee0e3;
490
+ }
491
+ .universal-card-markdown-list { text-align: left; }
492
+ .universal-card-markdown-list__item { align-items: flex-start; }
493
+ .universal-card-markdown-list__marker { color: #1456f0; line-height: 1.6; }
494
+ .universal-card-markdown-list__li-content { display: inline-block; }
495
+ .universal-card-code-span {
496
+ border-radius: 4px; border: 1px solid #dee0e3; padding: 0 4px;
497
+ background-color: #f5f6f7; font-family: Menlo, Consolas, monospace; font-size: 13px;
498
+ }
499
+ .universal-card-markdown-code-block {
500
+ text-align: left; padding: 12px; min-width: 210px; margin: 4px 0;
501
+ font-size: 13px; font-weight: 400; line-height: 1.5;
502
+ background-color: #f5f6f7; border-radius: 6px; overflow-x: auto;
503
+ font-family: Menlo, Consolas, monospace; white-space: pre;
504
+ }
505
+ .universal-card-emoji { display: inline; }
506
+ /* emoji 雪碧图:<i> 的 background-image/size/position/width 由 emoji.css(larkw-emoji__img--emoji-*)提供;
507
+ 这里只管行内对齐(vertical-align 让表情与文字基线大致对齐)。 */
508
+ .universal-card-emoji__img { display: inline-block; vertical-align: -0.15em; }
509
+
510
+ /* 图标(standard_icon / ud_icon):glyph 由图标字体 :before 画出。
511
+ 字体 @font-face 与每图标 content 规则随 JS 注入(浏览器端 renderCard 自动注入,
512
+ Node/SSR 端引入 open-feishu-card/icon-font.css)。这里只管布局对齐。 */
513
+ .universal-card-icon {
514
+ display: inline-flex;
515
+ align-items: center;
516
+ justify-content: center;
517
+ vertical-align: -0.125em;
518
+ }
519
+
520
+ /* ---- chart 图表 ---- */
521
+ /* 挂载容器:aspect-ratio / height 由内联 style 给(来自 aspect_ratio)。
522
+ VChart 水合后会往 __vchart 里塞 <canvas>;水合前显示 loading 占位。 */
523
+ .universal-card-chart {
524
+ position: relative;
525
+ width: 100%;
526
+ box-sizing: border-box;
527
+ overflow: hidden;
528
+ }
529
+ .universal-card-chart__vchart {
530
+ position: relative;
531
+ width: 100%;
532
+ height: 100%;
533
+ display: block;
534
+ }
535
+ .universal-card-chart__vchart canvas { display: block; }
536
+ .universal-card-chart__loading,
537
+ .universal-card-chart__placeholder {
538
+ display: flex; align-items: center; justify-content: center;
539
+ width: 100%; height: 100%;
540
+ color: #8f959e; font-size: 12px;
541
+ background: #f5f6f7; border: 1px dashed #dee0e3; border-radius: 4px;
542
+ box-sizing: border-box;
543
+ }
544
+
545
+ /* ---- table 表格 ---- */
546
+ .universal-card-table {
547
+ width: 100%;
548
+ box-sizing: border-box;
549
+ border: 1px solid #dee0e3;
550
+ border-radius: 6px;
551
+ overflow: hidden;
552
+ }
553
+ .universal-card-table__scroll { width: 100%; overflow-x: auto; }
554
+ .universal-card-table__table {
555
+ width: 100%;
556
+ border-collapse: collapse;
557
+ table-layout: auto;
558
+ font-size: 14px;
559
+ color: #1f2329;
560
+ }
561
+ .universal-card-table__th,
562
+ .universal-card-table__td {
563
+ padding: 8px 12px;
564
+ border-bottom: 1px solid #dee0e3;
565
+ border-right: 1px solid #eff0f1;
566
+ vertical-align: middle;
567
+ box-sizing: border-box;
568
+ }
569
+ .universal-card-table__th:last-child,
570
+ .universal-card-table__td:last-child { border-right: none; }
571
+ .universal-card-table__tbody tr:last-child .universal-card-table__td { border-bottom: none; }
572
+ .universal-card-table__th {
573
+ font-size: 14px;
574
+ line-height: 22px;
575
+ white-space: nowrap;
576
+ color: #1f2329;
577
+ }
578
+ .universal-card-table__th-text--bold { font-weight: 600; }
579
+ .universal-card-table__cell {
580
+ display: flex;
581
+ align-items: center;
582
+ gap: 4px;
583
+ word-break: break-word;
584
+ }
585
+ .universal-card-table__tags { display: inline-flex; flex-wrap: wrap; gap: 4px; align-items: center; }
586
+
587
+ /* 暗色主题下的表格/图表占位 */
588
+ .universal-card-root.theme-dark .universal-card-table { border-color: #2e2e30; }
589
+ .universal-card-root.theme-dark .universal-card-table__th,
590
+ .universal-card-root.theme-dark .universal-card-table__td { border-color: #2e2e30; color: #d6d6d6; }
591
+ .universal-card-root.theme-dark .universal-card-table__th { color: #ebebeb; }
592
+ .universal-card-root.theme-dark .universal-card-chart__loading,
593
+ .universal-card-root.theme-dark .universal-card-chart__placeholder {
594
+ background: #232323; border-color: #2e2e30; color: #8a8a8a;
595
+ }
596
+
597
+ /* ---- 暗色主题(可选):给 .universal-card-root 加 .theme-dark 即可 ----
598
+ 暗色高光图同样由 JS 注入;如需纯 CSS 暗色,可自行覆盖 background-image。 */
599
+ .universal-card-root.theme-dark {
600
+ color: #ebebeb;
601
+ background-color: #1a1a1a;
602
+ border-color: #2e2e30;
603
+ }
604
+ .universal-card-root.theme-dark .universal-card-markdown { color: #d6d6d6; }
605
+ .universal-card-root.theme-dark .universal-card-hr { background-color: #2e2e30; }