@cyberpunk-vue/theme-chalk 1.14.0 → 1.14.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.
Files changed (47) hide show
  1. package/dist/index.css +1 -1
  2. package/dist/index.css.map +1 -1
  3. package/package.json +1 -1
  4. package/src/common/var.scss +247 -247
  5. package/src/components/avatar-group.scss +113 -113
  6. package/src/components/avatar.scss +123 -123
  7. package/src/components/badge.scss +210 -210
  8. package/src/components/breadcrumb.scss +203 -203
  9. package/src/components/button.scss +975 -975
  10. package/src/components/card.scss +696 -696
  11. package/src/components/checkbox-group.scss +22 -22
  12. package/src/components/checkbox.scss +320 -320
  13. package/src/components/col.scss +43 -43
  14. package/src/components/dialog.scss +359 -359
  15. package/src/components/divider.scss +250 -250
  16. package/src/components/empty.scss +99 -99
  17. package/src/components/form-item.scss +189 -189
  18. package/src/components/form.scss +59 -59
  19. package/src/components/icon.scss +83 -83
  20. package/src/components/image-preview.scss +147 -147
  21. package/src/components/image.scss +351 -351
  22. package/src/components/input-number.scss +129 -129
  23. package/src/components/input.scss +362 -362
  24. package/src/components/loading.scss +64 -64
  25. package/src/components/notification.scss +348 -348
  26. package/src/components/pagination.scss +287 -280
  27. package/src/components/pattern-background.scss +18 -18
  28. package/src/components/popover.scss +438 -438
  29. package/src/components/progress.scss +438 -438
  30. package/src/components/radio-group.scss +22 -22
  31. package/src/components/radio.scss +286 -286
  32. package/src/components/row.scss +12 -12
  33. package/src/components/scrollbar.scss +40 -40
  34. package/src/components/segmented.scss +566 -566
  35. package/src/components/select.scss +15 -1
  36. package/src/components/slider.scss +421 -421
  37. package/src/components/status-indicator.scss +206 -206
  38. package/src/components/switch.scss +405 -405
  39. package/src/components/table.scss +474 -474
  40. package/src/components/tag.scss +416 -416
  41. package/src/components/text.scss +310 -271
  42. package/src/components/textarea.scss +106 -104
  43. package/src/components/timeline.scss +379 -379
  44. package/src/components/tree.scss +397 -397
  45. package/src/components/upload.scss +509 -509
  46. package/src/index.scss +60 -60
  47. package/src/mixins/mixins.scss +156 -156
@@ -1,146 +1,146 @@
1
- // CpCard 组件样式
2
- // 赛博朋克/机甲风格卡片容器
3
-
4
- @use '../common/var' as *;
5
- @use '../mixins/mixins' as *;
6
-
7
- @include b(card) {
8
- // 基础样式
9
- --cp-card-color: var(--cp-border);
10
- --cp-card-color-light: rgba(255, 255, 255, 0.1);
11
- --cp-card-bg: var(--cp-bg-elevated);
1
+ // CpCard 组件样式
2
+ // 赛博朋克/机甲风格卡片容器
3
+
4
+ @use '../common/var' as *;
5
+ @use '../mixins/mixins' as *;
6
+
7
+ @include b(card) {
8
+ // 基础样式
9
+ --cp-card-color: var(--cp-border);
10
+ --cp-card-color-light: rgba(255, 255, 255, 0.1);
11
+ --cp-card-bg: var(--cp-bg-elevated);
12
12
  --cp-card-shadow-color: color-mix(in srgb, var(--cp-card-color) 44%, transparent);
13
- --cp-card-clip-path: polygon(12px 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%, 0 12px);
14
-
15
- position: relative;
16
- display: flex;
17
- flex-direction: column;
18
-
19
- // 🚀 核心修复 1:重置 flex 默认的 min-height: auto
20
- // 彻底解决示例三“展开状态下会始终将卡片二挤到容器外”的问题,允许卡片受限收缩
21
- min-width: 0;
22
- min-height: 0;
23
-
24
- // 🚀 核心修复 2:彻底移除错误的 flex 和 height 过渡!
25
- // 浏览器不支持 auto 高度的动画,强加过渡会导致渲染出错,修复“高度从 0 开始”的 Bug
13
+ --cp-card-clip-path: polygon(12px 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%, 0 12px);
14
+
15
+ position: relative;
16
+ display: flex;
17
+ flex-direction: column;
18
+
19
+ // 🚀 核心修复 1:重置 flex 默认的 min-height: auto
20
+ // 彻底解决示例三“展开状态下会始终将卡片二挤到容器外”的问题,允许卡片受限收缩
21
+ min-width: 0;
22
+ min-height: 0;
23
+
24
+ // 🚀 核心修复 2:彻底移除错误的 flex 和 height 过渡!
25
+ // 浏览器不支持 auto 高度的动画,强加过渡会导致渲染出错,修复“高度从 0 开始”的 Bug
26
26
  transition:
27
27
  transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
28
28
  color var(--cp-card-dimmed-duration, 0.3s) ease,
29
29
  filter var(--cp-card-dimmed-duration, 0.3s) ease,
30
30
  box-shadow var(--cp-card-dimmed-duration, 0.3s) ease;
31
-
32
- @include e(container) {
33
- position: relative;
34
- display: flex;
35
- flex-direction: column;
36
- flex: 1;
37
-
38
- // 🚀 同步解除内部容器的 Flex 最小限制
39
- min-width: 0;
40
- min-height: 0;
41
-
42
- background: var(--cp-card-bg);
43
- border: 1px solid var(--cp-card-border-color, var(--cp-border));
44
- color: var(--cp-text-primary);
45
-
46
- // 🚀 同样移除此处错误的 flex 过渡
47
- transition:
48
- background var(--cp-card-dimmed-duration, 0.3s) ease,
49
- border-color var(--cp-card-dimmed-duration, 0.3s) ease,
50
- color var(--cp-card-dimmed-duration, 0.3s) ease,
51
- filter 0.4s ease,
52
- opacity 0.4s ease;
53
-
54
- width: 100%;
55
- // 🚀 修复 3:移除原先的 height: 100%!
56
- // 只要有 flex: 1 就能自动撑满。如果保留 100%,在父级折叠高度变化时极易引发内部高度塌陷计算 Bug。
57
- overflow: hidden;
58
- transform: translateZ(0);
59
- backface-visibility: hidden;
60
- will-change: clip-path, filter;
61
-
62
- clip-path: var(--cp-card-clip-path);
63
- }
64
-
65
- // 类型变体控制颜色变量
66
- @each $type in (primary, success, warning, error, info) {
67
- &.cp-card--#{$type} {
68
- --cp-card-color: var(--cp-color-#{$type});
69
- --cp-card-color-light: var(--cp-color-#{$type}-light);
70
- }
71
- }
72
-
73
- isolation: isolate;
74
-
75
- &::before {
76
- content: '';
77
- position: absolute;
78
- inset: 0;
79
- z-index: -1;
80
- background: var(--cp-card-shadow-color);
81
- opacity: 0;
82
- transition: opacity 0.3s ease;
83
- pointer-events: none;
84
- display: none;
85
- }
86
-
87
- &::after {
88
- content: '';
89
- position: absolute;
90
- top: 0;
91
- right: 0;
92
- width: 10px;
93
- height: 10px;
94
- background: var(--cp-card-color);
95
- opacity: 0.4;
96
- z-index: 2;
97
- transition: all 0.3s ease;
98
- }
99
-
100
- &:hover {
101
- &::after {
102
- opacity: 1;
103
- }
104
- }
105
-
106
- // ===== 变体 =====
107
- @include m(solid) {
108
- > .cp-card__container {
109
- background: var(--cp-card-bg);
110
- border-color: var(--cp-border);
111
-
112
- &::before {
113
- content: '';
114
- position: absolute;
115
- top: 0;
116
- left: 0;
117
- width: 100%;
118
- height: 48px;
119
- background: linear-gradient(to bottom, var(--cp-card-color) 2px, var(--cp-card-color-light) 2px, transparent 100%);
120
- opacity: 0;
121
- transition: opacity 0.3s ease;
122
- pointer-events: none;
123
- z-index: 1;
124
- }
125
- }
126
-
127
- &.cp-card--primary,
128
- &.cp-card--success,
129
- &.cp-card--warning,
130
- &.cp-card--error,
131
- &.cp-card--info {
132
- > .cp-card__container::before {
133
- opacity: 0.8;
134
- }
135
- }
136
-
137
- &[style*='--cp-card-color'] {
138
- > .cp-card__container::before {
139
- opacity: 0.8;
140
- }
141
- }
142
- }
143
-
31
+
32
+ @include e(container) {
33
+ position: relative;
34
+ display: flex;
35
+ flex-direction: column;
36
+ flex: 1;
37
+
38
+ // 🚀 同步解除内部容器的 Flex 最小限制
39
+ min-width: 0;
40
+ min-height: 0;
41
+
42
+ background: var(--cp-card-bg);
43
+ border: 1px solid var(--cp-card-border-color, var(--cp-border));
44
+ color: var(--cp-text-primary);
45
+
46
+ // 🚀 同样移除此处错误的 flex 过渡
47
+ transition:
48
+ background var(--cp-card-dimmed-duration, 0.3s) ease,
49
+ border-color var(--cp-card-dimmed-duration, 0.3s) ease,
50
+ color var(--cp-card-dimmed-duration, 0.3s) ease,
51
+ filter 0.4s ease,
52
+ opacity 0.4s ease;
53
+
54
+ width: 100%;
55
+ // 🚀 修复 3:移除原先的 height: 100%!
56
+ // 只要有 flex: 1 就能自动撑满。如果保留 100%,在父级折叠高度变化时极易引发内部高度塌陷计算 Bug。
57
+ overflow: hidden;
58
+ transform: translateZ(0);
59
+ backface-visibility: hidden;
60
+ will-change: clip-path, filter;
61
+
62
+ clip-path: var(--cp-card-clip-path);
63
+ }
64
+
65
+ // 类型变体控制颜色变量
66
+ @each $type in (primary, success, warning, error, info) {
67
+ &.cp-card--#{$type} {
68
+ --cp-card-color: var(--cp-color-#{$type});
69
+ --cp-card-color-light: var(--cp-color-#{$type}-light);
70
+ }
71
+ }
72
+
73
+ isolation: isolate;
74
+
75
+ &::before {
76
+ content: '';
77
+ position: absolute;
78
+ inset: 0;
79
+ z-index: -1;
80
+ background: var(--cp-card-shadow-color);
81
+ opacity: 0;
82
+ transition: opacity 0.3s ease;
83
+ pointer-events: none;
84
+ display: none;
85
+ }
86
+
87
+ &::after {
88
+ content: '';
89
+ position: absolute;
90
+ top: 0;
91
+ right: 0;
92
+ width: 10px;
93
+ height: 10px;
94
+ background: var(--cp-card-color);
95
+ opacity: 0.4;
96
+ z-index: 2;
97
+ transition: all 0.3s ease;
98
+ }
99
+
100
+ &:hover {
101
+ &::after {
102
+ opacity: 1;
103
+ }
104
+ }
105
+
106
+ // ===== 变体 =====
107
+ @include m(solid) {
108
+ > .cp-card__container {
109
+ background: var(--cp-card-bg);
110
+ border-color: var(--cp-border);
111
+
112
+ &::before {
113
+ content: '';
114
+ position: absolute;
115
+ top: 0;
116
+ left: 0;
117
+ width: 100%;
118
+ height: 48px;
119
+ background: linear-gradient(to bottom, var(--cp-card-color) 2px, var(--cp-card-color-light) 2px, transparent 100%);
120
+ opacity: 0;
121
+ transition: opacity 0.3s ease;
122
+ pointer-events: none;
123
+ z-index: 1;
124
+ }
125
+ }
126
+
127
+ &.cp-card--primary,
128
+ &.cp-card--success,
129
+ &.cp-card--warning,
130
+ &.cp-card--error,
131
+ &.cp-card--info {
132
+ > .cp-card__container::before {
133
+ opacity: 0.8;
134
+ }
135
+ }
136
+
137
+ &[style*='--cp-card-color'] {
138
+ > .cp-card__container::before {
139
+ opacity: 0.8;
140
+ }
141
+ }
142
+ }
143
+
144
144
  @include m(outline) {
145
145
  > .cp-card__container {
146
146
  background: transparent;
@@ -151,117 +151,117 @@
151
151
  box-shadow: none;
152
152
  }
153
153
  }
154
-
155
- &.cp-card--default {
156
- > .cp-card__container {
157
- border-color: var(--cp-border);
158
- }
159
- }
160
- }
161
-
162
- @include m(semi) {
163
- --cp-card-bg: color-mix(in srgb, var(--cp-border) 50%, transparent);
164
- --cp-card-bg-hover: color-mix(in srgb, var(--cp-border) 70%, transparent);
165
- --cp-card-border: var(--cp-border);
166
-
167
- > .cp-card__container {
168
- background: var(--cp-card-bg);
169
- backdrop-filter: blur(10px);
170
- border-color: var(--cp-card-border);
171
-
172
- &:hover {
173
- background: var(--cp-card-bg-hover);
174
- box-shadow: 0 0 15px var(--cp-card-color-light);
175
- }
176
- }
177
-
178
- &.cp-card--primary,
179
- &.cp-card--success,
180
- &.cp-card--warning,
181
- &.cp-card--error,
182
- &.cp-card--info {
183
- --cp-card-bg: color-mix(in srgb, var(--cp-bg-elevated) 85%, var(--cp-card-color));
184
- --cp-card-bg-hover: color-mix(in srgb, var(--cp-bg-elevated) 75%, var(--cp-card-color));
185
- --cp-card-border: var(--cp-card-color-light);
186
- }
187
- }
188
-
189
- @include m(ghost) {
190
- > .cp-card__container {
191
- background: transparent;
192
- border-color: transparent;
193
-
194
- &:hover {
195
- background: var(--cp-bg-elevated);
196
- border-color: var(--cp-card-color-light);
197
- }
198
- }
199
-
200
- &.cp-card--primary,
201
- &.cp-card--success,
202
- &.cp-card--warning,
203
- &.cp-card--error,
204
- &.cp-card--info {
205
- --cp-card-divider-color: var(--cp-card-color-light);
206
- }
207
-
208
- &[style*='--cp-card-color'] {
209
- --cp-card-divider-color: var(--cp-card-color-light);
210
- }
211
-
212
- &::after {
213
- display: none;
214
- }
215
- }
216
-
217
- // ===== 形状模式 =====
218
- @include m(shape-clip) {
219
- > .cp-card__container {
220
- clip-path: var(--cp-card-clip-path);
221
- }
222
- &::before {
223
- clip-path: var(--cp-card-clip-path);
224
- }
225
- }
226
-
154
+
155
+ &.cp-card--default {
156
+ > .cp-card__container {
157
+ border-color: var(--cp-border);
158
+ }
159
+ }
160
+ }
161
+
162
+ @include m(semi) {
163
+ --cp-card-bg: color-mix(in srgb, var(--cp-border) 50%, transparent);
164
+ --cp-card-bg-hover: color-mix(in srgb, var(--cp-border) 70%, transparent);
165
+ --cp-card-border: var(--cp-border);
166
+
167
+ > .cp-card__container {
168
+ background: var(--cp-card-bg);
169
+ backdrop-filter: blur(10px);
170
+ border-color: var(--cp-card-border);
171
+
172
+ &:hover {
173
+ background: var(--cp-card-bg-hover);
174
+ box-shadow: 0 0 15px var(--cp-card-color-light);
175
+ }
176
+ }
177
+
178
+ &.cp-card--primary,
179
+ &.cp-card--success,
180
+ &.cp-card--warning,
181
+ &.cp-card--error,
182
+ &.cp-card--info {
183
+ --cp-card-bg: color-mix(in srgb, var(--cp-bg-elevated) 85%, var(--cp-card-color));
184
+ --cp-card-bg-hover: color-mix(in srgb, var(--cp-bg-elevated) 75%, var(--cp-card-color));
185
+ --cp-card-border: var(--cp-card-color-light);
186
+ }
187
+ }
188
+
189
+ @include m(ghost) {
190
+ > .cp-card__container {
191
+ background: transparent;
192
+ border-color: transparent;
193
+
194
+ &:hover {
195
+ background: var(--cp-bg-elevated);
196
+ border-color: var(--cp-card-color-light);
197
+ }
198
+ }
199
+
200
+ &.cp-card--primary,
201
+ &.cp-card--success,
202
+ &.cp-card--warning,
203
+ &.cp-card--error,
204
+ &.cp-card--info {
205
+ --cp-card-divider-color: var(--cp-card-color-light);
206
+ }
207
+
208
+ &[style*='--cp-card-color'] {
209
+ --cp-card-divider-color: var(--cp-card-color-light);
210
+ }
211
+
212
+ &::after {
213
+ display: none;
214
+ }
215
+ }
216
+
217
+ // ===== 形状模式 =====
218
+ @include m(shape-clip) {
219
+ > .cp-card__container {
220
+ clip-path: var(--cp-card-clip-path);
221
+ }
222
+ &::before {
223
+ clip-path: var(--cp-card-clip-path);
224
+ }
225
+ }
226
+
227
227
  @include m(shape-no-clip) {
228
228
  border-radius: 0;
229
229
 
230
230
  > .cp-card__container {
231
231
  clip-path: none;
232
232
  border-radius: 0;
233
- overflow: hidden;
234
- }
235
-
236
- &::before {
237
- clip-path: none;
238
- border-radius: 0;
239
- }
240
-
241
- &::after {
242
- display: none;
243
- }
244
- }
245
-
233
+ overflow: hidden;
234
+ }
235
+
236
+ &::before {
237
+ clip-path: none;
238
+ border-radius: 0;
239
+ }
240
+
241
+ &::after {
242
+ display: none;
243
+ }
244
+ }
245
+
246
246
  @include m(shape-round) {
247
247
  border-radius: var(--cp-radius-lg);
248
248
 
249
249
  > .cp-card__container {
250
250
  clip-path: none;
251
251
  border-radius: var(--cp-radius-lg);
252
- overflow: hidden;
253
- }
254
-
255
- &::before {
256
- clip-path: none;
257
- border-radius: var(--cp-radius-lg);
258
- }
259
-
260
- &::after {
261
- display: none;
262
- }
263
- }
264
-
252
+ overflow: hidden;
253
+ }
254
+
255
+ &::before {
256
+ clip-path: none;
257
+ border-radius: var(--cp-radius-lg);
258
+ }
259
+
260
+ &::after {
261
+ display: none;
262
+ }
263
+ }
264
+
265
265
  // ===== 阴影 =====
266
266
  @include m(shadow-always) {
267
267
  filter: none;
@@ -361,189 +361,189 @@
361
361
  }
362
362
 
363
363
  // ===== 子元素 =====
364
- @include e(cover) {
365
- width: 100%;
366
- overflow: hidden;
367
- flex-shrink: 0;
368
- border-bottom: 1px solid var(--cp-border);
369
-
370
- img {
371
- width: 100%;
372
- height: 100%;
373
- display: block;
374
- object-fit: cover;
375
- }
376
- }
377
-
378
- @include e(header) {
379
- display: flex;
380
- align-items: center;
381
- justify-content: space-between;
382
- padding: var(--cp-spacing-md) var(--cp-spacing-lg);
383
- min-height: 48px;
384
- transition: border-color var(--cp-card-dimmed-duration, 0.3s) ease;
385
-
386
- &.is-bordered {
387
- border-bottom: 1px solid var(--cp-card-header-divider-color, var(--cp-card-divider-color, var(--cp-border)));
388
- }
389
- }
390
-
391
- @include e(title) {
392
- font-family: var(--cp-font-family-display);
393
- font-weight: 600;
394
- font-size: var(--cp-font-size-lg);
395
- text-transform: uppercase;
396
- letter-spacing: 0.05em;
397
- color: var(--cp-text-primary);
398
- }
399
-
400
- @include e(extra) {
401
- display: flex;
402
- align-items: center;
403
- gap: var(--cp-spacing-sm);
404
- }
405
-
406
- @include e(body) {
407
- display: flex;
408
- flex-direction: column;
409
- flex: 1;
410
- // 🚀 同步解除 body 层的最小高度限制,配合内部可能出现的滚动条
411
- min-height: 0;
412
- padding: var(--cp-spacing-md);
413
- color: var(--cp-text-secondary);
414
- }
415
-
416
- @include e(footer) {
417
- display: flex;
418
- align-items: center;
419
- justify-content: flex-end;
420
- padding: var(--cp-spacing-md) var(--cp-spacing-lg);
421
- gap: var(--cp-spacing-sm);
422
- transition: border-color var(--cp-card-dimmed-duration, 0.3s) ease;
423
-
424
- &.is-bordered {
425
- border-top: 1px solid var(--cp-card-footer-divider-color, var(--cp-card-divider-color, var(--cp-border)));
426
- }
427
- }
428
-
429
- // ===== 覆层背景遮罩 =====
430
- @include e(overlay-backdrop) {
431
- position: absolute;
432
- inset: 0;
433
- z-index: 9;
434
- opacity: 0;
435
- pointer-events: none;
436
- transition-property: opacity, backdrop-filter, background;
437
- transition-duration: var(--cp-card-overlay-duration, 300ms);
438
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
439
-
440
- &.cp-card__overlay-backdrop--effect-none { background: transparent; backdrop-filter: none; }
441
- &.cp-card__overlay-backdrop--effect-blur { background: transparent; backdrop-filter: blur(var(--cp-card-overlay-blur, 10px)); }
442
- &.cp-card__overlay-backdrop--effect-color { background: var(--cp-card-overlay-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: none; }
443
- &.cp-card__overlay-backdrop--effect-blur-color { background: var(--cp-card-overlay-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: blur(var(--cp-card-overlay-blur, 10px)); }
444
- }
445
-
446
- // ===== 覆层操作区 =====
447
- @include e(overlay) {
448
- position: absolute;
449
- left: 0;
450
- right: 0;
451
- z-index: 10;
452
- padding: var(--cp-spacing-md) var(--cp-spacing-lg);
453
- border-top: 1px solid var(--cp-border);
454
- opacity: 0;
455
- pointer-events: none;
456
- transition-property: opacity, transform, backdrop-filter, background;
457
- transition-duration: var(--cp-card-overlay-duration, 300ms);
458
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
459
-
460
- &.cp-card__overlay--effect-none { background: transparent; backdrop-filter: none; }
461
- &.cp-card__overlay--effect-blur { background: transparent; backdrop-filter: blur(var(--cp-card-action-blur, 10px)); }
462
- &.cp-card__overlay--effect-color { background: var(--cp-card-action-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: none; }
463
- &.cp-card__overlay--effect-blur-color { background: var(--cp-card-action-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: blur(var(--cp-card-action-blur, 10px)); }
464
-
465
- &.cp-card__overlay--bottom { bottom: 0; }
466
- &.cp-card__overlay--top { top: 0; border-top: none; border-bottom: 1px solid var(--cp-border); }
467
- &.cp-card__overlay--center { top: 50%; border-top: none; border-bottom: none; }
468
-
469
- &.cp-card__overlay--slide-up { transform: translateY(100%); }
470
- &.cp-card__overlay--slide-down { transform: translateY(-100%); }
471
- &.cp-card__overlay--slide-left { transform: translateX(100%); }
472
- &.cp-card__overlay--slide-right { transform: translateX(-100%); }
473
-
474
- &.cp-card__overlay--fade { transform: none; }
475
- &.cp-card__overlay--scale {
476
- transform: scale(0.9);
477
- &.cp-card__overlay--center {
478
- transform: translateY(-50%) scale(0.9);
479
- }
480
- }
481
- }
482
-
483
- &.is-has-overlay:hover {
484
- .cp-card__overlay-backdrop { opacity: 1; }
485
- .cp-card__overlay {
486
- opacity: 1;
487
- pointer-events: auto;
488
- transform: translateY(0) translateX(0) scale(1);
489
- &.cp-card__overlay--center { transform: translateY(-50%); }
490
- }
491
- }
492
-
493
- // ===== 减淡模式 (Dimmed Mode) =====
494
- @include when(dimmed) {
495
- &:not(:hover) {
496
- --cp-card-color: var(--cp-border);
497
- --cp-card-color-light: rgba(255, 255, 255, 0.1);
498
-
499
- &.cp-card--semi {
500
- --cp-card-bg: color-mix(in srgb, var(--cp-border) 50%, transparent);
501
- --cp-card-border: var(--cp-border);
502
- }
503
-
504
- &.cp-card--solid {
505
- > .cp-card__container::before { opacity: 0 !important; }
506
- }
507
-
508
- &.cp-card--outline {
509
- > .cp-card__container { border-color: var(--cp-border); }
510
- }
511
-
512
- &.cp-card--ghost {
513
- --cp-card-divider-color: var(--cp-border);
514
- }
515
- }
516
- }
517
-
518
- @include when(trigger-image-hover) {
519
- &:hover {
520
- .cp-image--hover-scale {
521
- transform: scale(1.02);
522
- box-shadow: 0 0 20px var(--cp-image-decor-color, var(--cp-color-primary-light));
523
- filter: brightness(1.05);
524
-
525
- .cp-image__decor {
526
- background-color: var(--cp-image-decor-color, var(--cp-color-primary));
527
- box-shadow: 0 0 8px var(--cp-image-decor-color, var(--cp-color-primary));
528
- }
529
- }
530
-
531
- .cp-image--hover-zoom {
532
- box-shadow: 0 0 20px var(--cp-image-decor-color, var(--cp-color-primary-light));
533
-
534
- .cp-image__inner {
535
- transform: scale(1.1);
536
- filter: brightness(1.05);
537
- }
538
-
539
- .cp-image__decor {
540
- background-color: var(--cp-image-decor-color, var(--cp-color-primary));
541
- box-shadow: 0 0 8px var(--cp-image-decor-color, var(--cp-color-primary));
542
- }
543
- }
544
- }
545
- }
546
-
364
+ @include e(cover) {
365
+ width: 100%;
366
+ overflow: hidden;
367
+ flex-shrink: 0;
368
+ border-bottom: 1px solid var(--cp-border);
369
+
370
+ img {
371
+ width: 100%;
372
+ height: 100%;
373
+ display: block;
374
+ object-fit: cover;
375
+ }
376
+ }
377
+
378
+ @include e(header) {
379
+ display: flex;
380
+ align-items: center;
381
+ justify-content: space-between;
382
+ padding: var(--cp-spacing-md) var(--cp-spacing-lg);
383
+ min-height: 48px;
384
+ transition: border-color var(--cp-card-dimmed-duration, 0.3s) ease;
385
+
386
+ &.is-bordered {
387
+ border-bottom: 1px solid var(--cp-card-header-divider-color, var(--cp-card-divider-color, var(--cp-border)));
388
+ }
389
+ }
390
+
391
+ @include e(title) {
392
+ font-family: var(--cp-font-family-display);
393
+ font-weight: 600;
394
+ font-size: var(--cp-font-size-lg);
395
+ text-transform: uppercase;
396
+ letter-spacing: 0.05em;
397
+ color: var(--cp-text-primary);
398
+ }
399
+
400
+ @include e(extra) {
401
+ display: flex;
402
+ align-items: center;
403
+ gap: var(--cp-spacing-sm);
404
+ }
405
+
406
+ @include e(body) {
407
+ display: flex;
408
+ flex-direction: column;
409
+ flex: 1;
410
+ // 🚀 同步解除 body 层的最小高度限制,配合内部可能出现的滚动条
411
+ min-height: 0;
412
+ padding: var(--cp-spacing-md);
413
+ color: var(--cp-text-secondary);
414
+ }
415
+
416
+ @include e(footer) {
417
+ display: flex;
418
+ align-items: center;
419
+ justify-content: flex-end;
420
+ padding: var(--cp-spacing-md) var(--cp-spacing-lg);
421
+ gap: var(--cp-spacing-sm);
422
+ transition: border-color var(--cp-card-dimmed-duration, 0.3s) ease;
423
+
424
+ &.is-bordered {
425
+ border-top: 1px solid var(--cp-card-footer-divider-color, var(--cp-card-divider-color, var(--cp-border)));
426
+ }
427
+ }
428
+
429
+ // ===== 覆层背景遮罩 =====
430
+ @include e(overlay-backdrop) {
431
+ position: absolute;
432
+ inset: 0;
433
+ z-index: 9;
434
+ opacity: 0;
435
+ pointer-events: none;
436
+ transition-property: opacity, backdrop-filter, background;
437
+ transition-duration: var(--cp-card-overlay-duration, 300ms);
438
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
439
+
440
+ &.cp-card__overlay-backdrop--effect-none { background: transparent; backdrop-filter: none; }
441
+ &.cp-card__overlay-backdrop--effect-blur { background: transparent; backdrop-filter: blur(var(--cp-card-overlay-blur, 10px)); }
442
+ &.cp-card__overlay-backdrop--effect-color { background: var(--cp-card-overlay-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: none; }
443
+ &.cp-card__overlay-backdrop--effect-blur-color { background: var(--cp-card-overlay-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: blur(var(--cp-card-overlay-blur, 10px)); }
444
+ }
445
+
446
+ // ===== 覆层操作区 =====
447
+ @include e(overlay) {
448
+ position: absolute;
449
+ left: 0;
450
+ right: 0;
451
+ z-index: 10;
452
+ padding: var(--cp-spacing-md) var(--cp-spacing-lg);
453
+ border-top: 1px solid var(--cp-border);
454
+ opacity: 0;
455
+ pointer-events: none;
456
+ transition-property: opacity, transform, backdrop-filter, background;
457
+ transition-duration: var(--cp-card-overlay-duration, 300ms);
458
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
459
+
460
+ &.cp-card__overlay--effect-none { background: transparent; backdrop-filter: none; }
461
+ &.cp-card__overlay--effect-blur { background: transparent; backdrop-filter: blur(var(--cp-card-action-blur, 10px)); }
462
+ &.cp-card__overlay--effect-color { background: var(--cp-card-action-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: none; }
463
+ &.cp-card__overlay--effect-blur-color { background: var(--cp-card-action-color, color-mix(in srgb, var(--cp-bg-deep) 80%, transparent)); backdrop-filter: blur(var(--cp-card-action-blur, 10px)); }
464
+
465
+ &.cp-card__overlay--bottom { bottom: 0; }
466
+ &.cp-card__overlay--top { top: 0; border-top: none; border-bottom: 1px solid var(--cp-border); }
467
+ &.cp-card__overlay--center { top: 50%; border-top: none; border-bottom: none; }
468
+
469
+ &.cp-card__overlay--slide-up { transform: translateY(100%); }
470
+ &.cp-card__overlay--slide-down { transform: translateY(-100%); }
471
+ &.cp-card__overlay--slide-left { transform: translateX(100%); }
472
+ &.cp-card__overlay--slide-right { transform: translateX(-100%); }
473
+
474
+ &.cp-card__overlay--fade { transform: none; }
475
+ &.cp-card__overlay--scale {
476
+ transform: scale(0.9);
477
+ &.cp-card__overlay--center {
478
+ transform: translateY(-50%) scale(0.9);
479
+ }
480
+ }
481
+ }
482
+
483
+ &.is-has-overlay:hover {
484
+ .cp-card__overlay-backdrop { opacity: 1; }
485
+ .cp-card__overlay {
486
+ opacity: 1;
487
+ pointer-events: auto;
488
+ transform: translateY(0) translateX(0) scale(1);
489
+ &.cp-card__overlay--center { transform: translateY(-50%); }
490
+ }
491
+ }
492
+
493
+ // ===== 减淡模式 (Dimmed Mode) =====
494
+ @include when(dimmed) {
495
+ &:not(:hover) {
496
+ --cp-card-color: var(--cp-border);
497
+ --cp-card-color-light: rgba(255, 255, 255, 0.1);
498
+
499
+ &.cp-card--semi {
500
+ --cp-card-bg: color-mix(in srgb, var(--cp-border) 50%, transparent);
501
+ --cp-card-border: var(--cp-border);
502
+ }
503
+
504
+ &.cp-card--solid {
505
+ > .cp-card__container::before { opacity: 0 !important; }
506
+ }
507
+
508
+ &.cp-card--outline {
509
+ > .cp-card__container { border-color: var(--cp-border); }
510
+ }
511
+
512
+ &.cp-card--ghost {
513
+ --cp-card-divider-color: var(--cp-border);
514
+ }
515
+ }
516
+ }
517
+
518
+ @include when(trigger-image-hover) {
519
+ &:hover {
520
+ .cp-image--hover-scale {
521
+ transform: scale(1.02);
522
+ box-shadow: 0 0 20px var(--cp-image-decor-color, var(--cp-color-primary-light));
523
+ filter: brightness(1.05);
524
+
525
+ .cp-image__decor {
526
+ background-color: var(--cp-image-decor-color, var(--cp-color-primary));
527
+ box-shadow: 0 0 8px var(--cp-image-decor-color, var(--cp-color-primary));
528
+ }
529
+ }
530
+
531
+ .cp-image--hover-zoom {
532
+ box-shadow: 0 0 20px var(--cp-image-decor-color, var(--cp-color-primary-light));
533
+
534
+ .cp-image__inner {
535
+ transform: scale(1.1);
536
+ filter: brightness(1.05);
537
+ }
538
+
539
+ .cp-image__decor {
540
+ background-color: var(--cp-image-decor-color, var(--cp-color-primary));
541
+ box-shadow: 0 0 8px var(--cp-image-decor-color, var(--cp-color-primary));
542
+ }
543
+ }
544
+ }
545
+ }
546
+
547
547
  @include when(hover-scale) {
548
548
  transition:
549
549
  transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
@@ -553,280 +553,280 @@
553
553
  &:hover {
554
554
  transform: scale(1.02);
555
555
  }
556
-
557
- &:active {
558
- transform: scale(0.99);
559
- }
560
- }
561
-
562
- // ===== 折叠过渡动画 (Collapse Transition) =====
563
- @include e(collapse-transition) {
564
- display: grid;
565
- flex: 1 1 auto;
566
- min-height: 0;
567
- overflow: hidden;
568
- grid-template-rows: 1fr;
569
- // 动态 max-height:由 JS ResizeObserver 测量实际内容高度并设为 CSS 变量,
570
- // 避免从 2000px 过渡导致的"两段式动画"视觉停顿
571
- max-height: var(--cp-card-expanded-height, none);
572
-
573
- // 预置 mask 渐变(200% 高),初始 position=top → 实心区域覆盖全部,无视觉效果
574
- // 半折叠时 position 滑到 bottom → 底部渐隐生效,实现渐显动画
575
- -webkit-mask-image: linear-gradient(to bottom, #000 50%, transparent 100%);
576
- mask-image: linear-gradient(to bottom, #000 50%, transparent 100%);
577
- -webkit-mask-size: 100% 200%;
578
- mask-size: 100% 200%;
579
- -webkit-mask-position: 0 0;
580
- mask-position: 0 0;
581
-
582
- transition:
583
- grid-template-rows 0.3s cubic-bezier(0.4, 0, 0.2, 1),
584
- max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
585
- -webkit-mask-position 0.3s cubic-bezier(0.4, 0, 0.2, 1),
586
- mask-position 0.3s cubic-bezier(0.4, 0, 0.2, 1),
587
- opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
588
- visibility 0.3s cubic-bezier(0.4, 0, 0.2, 1);
589
- visibility: visible;
590
- }
591
-
592
- @include e(collapse-inner) {
593
- min-height: 0;
594
- overflow: hidden;
595
- display: flex;
596
- flex-direction: column;
597
- flex: 1 1 auto;
598
- }
599
-
600
- // ===== 折叠时尺寸锁定 =====
601
- @include when(collapse-size-locked) {
602
- // 🚀 核心修复 4:将原来的 flex: 0 0 auto 改为 flex: 0 1 auto!
603
- // "1" 代表 flex-shrink: 1。允许卡片在展开动画的 0.3s 期间,如果碰到了固定父容器的边界,
604
- // 能够聪明地被压缩,彻底解决“示例二在展开时会把卡片二挤到容器外”的恶性 Bug。
605
- flex: 0 1 auto !important;
606
- height: auto !important;
607
- min-height: 0 !important;
608
- overflow: hidden !important;
609
-
610
- .cp-card__container {
611
- flex: 0 1 auto !important;
612
- height: auto !important;
613
- min-height: 0 !important;
614
- overflow: hidden !important;
615
- }
616
- }
617
-
618
- // ===== 折叠模式 (Collapsed) =====
619
- @include when(collapsed) {
620
- // 同步保持折叠态允许挤压的特性
621
- flex: 0 1 auto !important;
622
- height: auto !important;
623
- min-height: 0 !important;
624
- overflow: hidden !important;
625
-
626
- .cp-card__container {
627
- flex: 0 1 auto !important;
628
- height: auto !important;
629
- min-height: 0 !important;
630
- overflow: hidden !important;
631
- }
632
-
633
- .cp-card__header {
634
- border-bottom-color: transparent;
635
- transition-delay: 0s;
636
- }
637
-
638
- .cp-card__collapse-transition {
639
- grid-template-rows: 0fr;
640
- // 移除 max-height: 0; 避免 max-height 动画从 none 到 0 直接报错导致无动画(全折叠卡顿原因)
641
- opacity: 0;
642
- pointer-events: none;
643
- visibility: hidden;
644
- }
645
-
646
- // Overlay fades out when collapsed
647
- .cp-card__overlay-backdrop,
648
- .cp-card__overlay {
649
- opacity: 0;
650
- pointer-events: none;
651
- }
652
- }
653
-
654
- // ===== 半折叠模式 (Half-Collapsed) — collapse + halfCollapse =====
655
- // 覆写 collapsed 的 grid-template-rows: 0fr,保留部分 body 并用 mask-image 渐隐
656
- @include when(half-collapsed) {
657
- // 仅覆写 is-collapsed 的 flex-shrink 为 0,半折叠时禁止收缩,
658
- // 防止兄弟 Card 展开时将半折叠卡片压扁,同时保留原有的 overflow: hidden 以维持动画
659
- flex-shrink: 0 !important;
660
-
661
- .cp-card__container {
662
- flex-shrink: 0 !important;
663
- }
664
-
665
- .cp-card__collapse-transition {
666
- grid-template-rows: 1fr;
667
- max-height: var(--cp-card-peek-height, 80px);
668
- opacity: 1;
669
- visibility: visible;
670
- pointer-events: none;
671
-
672
- // mask-position 滑到底部 → 渐变区域覆盖底部 → 内容底部渐隐
673
- -webkit-mask-position: 0 100%;
674
- mask-position: 0 100%;
675
- }
676
-
677
- // 半折叠时隐藏 footer(在 collapse-transition 内部,pointer-events: none 导致不可交互)
678
- // 使用 opacity 和 visibility 代替 display: none,避免 DOM render 树的突变中断外层容器的展开收起动画
679
- .cp-card__footer {
680
- opacity: 0;
681
- visibility: hidden;
682
- pointer-events: none;
683
- }
684
-
685
- // 半折叠时保留 header 分隔线
686
- .cp-card__header {
687
- border-bottom-color: var(--cp-card-header-divider-color, var(--cp-card-divider-color, var(--cp-border)));
688
- }
689
-
690
- // 内置控制器悬浮于文字上方
691
- .cp-card__collapse-action {
692
- position: absolute;
693
- bottom: var(--cp-spacing-xs);
694
- left: 0;
695
- width: 100%;
696
- z-index: 10;
697
- }
698
- }
699
-
700
- // ===== 内置折叠控制器 (Collapse Action) =====
701
- @include e(collapse-action) {
702
- // 移除 border-top,依靠布局和渐变与内容融合
703
- }
704
-
705
- @include e(collapse-action-default) {
706
- display: flex;
707
- align-items: center;
708
- justify-content: center;
709
- gap: var(--cp-spacing-xs);
710
- padding: var(--cp-spacing-sm) var(--cp-spacing-md);
711
- cursor: pointer;
712
- user-select: none;
713
- color: var(--cp-text-tertiary);
714
- font-size: var(--cp-font-size-sm);
715
- letter-spacing: 0.04em;
716
- transition: color 0.2s ease, background 0.2s ease;
717
-
718
- &:hover {
719
- color: var(--cp-card-color, var(--cp-text-primary));
720
- background: color-mix(in srgb, var(--cp-card-color, var(--cp-text-primary)) 8%, transparent);
721
- }
722
- }
723
-
724
- @include e(collapse-action-text) {
725
- line-height: 1;
726
- }
727
-
728
- @include e(collapse-action-icon) {
729
- font-size: 10px;
730
- line-height: 1;
731
- transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
732
-
733
- &.is-expanded {
734
- transform: rotate(180deg);
735
- }
736
- }
737
-
738
- // ===== 加载遮罩 (Loading Overlay) =====
739
- @include e(loading-overlay) {
740
- position: absolute;
741
- inset: 0;
742
- z-index: 12;
743
- display: flex;
744
- flex-direction: column;
745
- align-items: center;
746
- justify-content: center;
747
- gap: var(--cp-spacing-sm);
748
- background: var(--cp-card-loading-bg, rgba(10, 10, 18, 0.75));
749
- backdrop-filter: var(--cp-card-loading-backdrop, blur(4px));
750
- pointer-events: auto;
751
- }
752
-
753
- @include e(loading-text) {
754
- font-size: var(--cp-font-size-sm);
755
- color: var(--cp-card-loading-text-color, var(--cp-text-secondary));
756
- letter-spacing: 0.05em;
757
- user-select: none;
758
- margin-top: var(--cp-spacing-xs);
759
- }
760
-
761
- // ===== 加载遮罩过渡动画 =====
762
- .cp-card-loading-enter-active,
763
- .cp-card-loading-leave-active {
764
- transition: opacity 0.3s ease;
765
- }
766
- .cp-card-loading-enter-from,
767
- .cp-card-loading-leave-to {
768
- opacity: 0;
769
- }
770
-
771
- // ===== 加载状态 (Loading) =====
772
- @include when(loading) {
773
- // loading 时仍可悬停查看效果,但内容被遮罩阻挡
774
- > .cp-card__container {
775
- // container 需要 position: relative 来定位 loading overlay
776
- position: relative;
777
- }
778
- }
779
-
780
- // ===== 禁用状态 (Disabled) =====
781
- @include when(disabled) {
782
- pointer-events: none;
783
- cursor: not-allowed;
784
-
785
- > .cp-card__container {
786
- opacity: 0.5;
787
- filter: grayscale(0.6);
788
- }
789
-
790
- // 加载遮罩也必须禁止 pointer-events,
791
- // 否则子元素 pointer-events: auto 会让 :hover 冒泡到卡片根节点
792
- .cp-card__loading-overlay {
793
- pointer-events: none !important;
794
- }
795
-
796
- // 装饰块始终保持低透明度
797
- &::after {
798
- opacity: 0.2 !important;
799
- }
800
-
801
- // 彻底禁止所有 hover 视觉反馈
802
- &:hover {
803
- // 阻止阴影 hover
804
- filter: none !important;
805
- box-shadow: none !important;
806
- // 阻止 hover-scale
807
- transform: none !important;
808
-
809
- // 装饰块不变亮
810
- &::after {
811
- opacity: 0.2 !important;
812
- }
813
-
814
- // 容器不响应 hover
815
- > .cp-card__container {
816
- border-color: inherit;
817
- box-shadow: none !important;
818
- filter: grayscale(0.6) !important;
819
- }
820
-
821
- // 覆层不弹出
822
- .cp-card__overlay-backdrop {
823
- opacity: 0 !important;
824
- }
825
- .cp-card__overlay {
826
- opacity: 0 !important;
827
- pointer-events: none !important;
828
- transform: none !important;
829
- }
830
- }
831
- }
832
- }
556
+
557
+ &:active {
558
+ transform: scale(0.99);
559
+ }
560
+ }
561
+
562
+ // ===== 折叠过渡动画 (Collapse Transition) =====
563
+ @include e(collapse-transition) {
564
+ display: grid;
565
+ flex: 1 1 auto;
566
+ min-height: 0;
567
+ overflow: hidden;
568
+ grid-template-rows: 1fr;
569
+ // 动态 max-height:由 JS ResizeObserver 测量实际内容高度并设为 CSS 变量,
570
+ // 避免从 2000px 过渡导致的"两段式动画"视觉停顿
571
+ max-height: var(--cp-card-expanded-height, none);
572
+
573
+ // 预置 mask 渐变(200% 高),初始 position=top → 实心区域覆盖全部,无视觉效果
574
+ // 半折叠时 position 滑到 bottom → 底部渐隐生效,实现渐显动画
575
+ -webkit-mask-image: linear-gradient(to bottom, #000 50%, transparent 100%);
576
+ mask-image: linear-gradient(to bottom, #000 50%, transparent 100%);
577
+ -webkit-mask-size: 100% 200%;
578
+ mask-size: 100% 200%;
579
+ -webkit-mask-position: 0 0;
580
+ mask-position: 0 0;
581
+
582
+ transition:
583
+ grid-template-rows 0.3s cubic-bezier(0.4, 0, 0.2, 1),
584
+ max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
585
+ -webkit-mask-position 0.3s cubic-bezier(0.4, 0, 0.2, 1),
586
+ mask-position 0.3s cubic-bezier(0.4, 0, 0.2, 1),
587
+ opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
588
+ visibility 0.3s cubic-bezier(0.4, 0, 0.2, 1);
589
+ visibility: visible;
590
+ }
591
+
592
+ @include e(collapse-inner) {
593
+ min-height: 0;
594
+ overflow: hidden;
595
+ display: flex;
596
+ flex-direction: column;
597
+ flex: 1 1 auto;
598
+ }
599
+
600
+ // ===== 折叠时尺寸锁定 =====
601
+ @include when(collapse-size-locked) {
602
+ // 🚀 核心修复 4:将原来的 flex: 0 0 auto 改为 flex: 0 1 auto!
603
+ // "1" 代表 flex-shrink: 1。允许卡片在展开动画的 0.3s 期间,如果碰到了固定父容器的边界,
604
+ // 能够聪明地被压缩,彻底解决“示例二在展开时会把卡片二挤到容器外”的恶性 Bug。
605
+ flex: 0 1 auto !important;
606
+ height: auto !important;
607
+ min-height: 0 !important;
608
+ overflow: hidden !important;
609
+
610
+ .cp-card__container {
611
+ flex: 0 1 auto !important;
612
+ height: auto !important;
613
+ min-height: 0 !important;
614
+ overflow: hidden !important;
615
+ }
616
+ }
617
+
618
+ // ===== 折叠模式 (Collapsed) =====
619
+ @include when(collapsed) {
620
+ // 同步保持折叠态允许挤压的特性
621
+ flex: 0 1 auto !important;
622
+ height: auto !important;
623
+ min-height: 0 !important;
624
+ overflow: hidden !important;
625
+
626
+ .cp-card__container {
627
+ flex: 0 1 auto !important;
628
+ height: auto !important;
629
+ min-height: 0 !important;
630
+ overflow: hidden !important;
631
+ }
632
+
633
+ .cp-card__header {
634
+ border-bottom-color: transparent;
635
+ transition-delay: 0s;
636
+ }
637
+
638
+ .cp-card__collapse-transition {
639
+ grid-template-rows: 0fr;
640
+ // 移除 max-height: 0; 避免 max-height 动画从 none 到 0 直接报错导致无动画(全折叠卡顿原因)
641
+ opacity: 0;
642
+ pointer-events: none;
643
+ visibility: hidden;
644
+ }
645
+
646
+ // Overlay fades out when collapsed
647
+ .cp-card__overlay-backdrop,
648
+ .cp-card__overlay {
649
+ opacity: 0;
650
+ pointer-events: none;
651
+ }
652
+ }
653
+
654
+ // ===== 半折叠模式 (Half-Collapsed) — collapse + halfCollapse =====
655
+ // 覆写 collapsed 的 grid-template-rows: 0fr,保留部分 body 并用 mask-image 渐隐
656
+ @include when(half-collapsed) {
657
+ // 仅覆写 is-collapsed 的 flex-shrink 为 0,半折叠时禁止收缩,
658
+ // 防止兄弟 Card 展开时将半折叠卡片压扁,同时保留原有的 overflow: hidden 以维持动画
659
+ flex-shrink: 0 !important;
660
+
661
+ .cp-card__container {
662
+ flex-shrink: 0 !important;
663
+ }
664
+
665
+ .cp-card__collapse-transition {
666
+ grid-template-rows: 1fr;
667
+ max-height: var(--cp-card-peek-height, 80px);
668
+ opacity: 1;
669
+ visibility: visible;
670
+ pointer-events: none;
671
+
672
+ // mask-position 滑到底部 → 渐变区域覆盖底部 → 内容底部渐隐
673
+ -webkit-mask-position: 0 100%;
674
+ mask-position: 0 100%;
675
+ }
676
+
677
+ // 半折叠时隐藏 footer(在 collapse-transition 内部,pointer-events: none 导致不可交互)
678
+ // 使用 opacity 和 visibility 代替 display: none,避免 DOM render 树的突变中断外层容器的展开收起动画
679
+ .cp-card__footer {
680
+ opacity: 0;
681
+ visibility: hidden;
682
+ pointer-events: none;
683
+ }
684
+
685
+ // 半折叠时保留 header 分隔线
686
+ .cp-card__header {
687
+ border-bottom-color: var(--cp-card-header-divider-color, var(--cp-card-divider-color, var(--cp-border)));
688
+ }
689
+
690
+ // 内置控制器悬浮于文字上方
691
+ .cp-card__collapse-action {
692
+ position: absolute;
693
+ bottom: var(--cp-spacing-xs);
694
+ left: 0;
695
+ width: 100%;
696
+ z-index: 10;
697
+ }
698
+ }
699
+
700
+ // ===== 内置折叠控制器 (Collapse Action) =====
701
+ @include e(collapse-action) {
702
+ // 移除 border-top,依靠布局和渐变与内容融合
703
+ }
704
+
705
+ @include e(collapse-action-default) {
706
+ display: flex;
707
+ align-items: center;
708
+ justify-content: center;
709
+ gap: var(--cp-spacing-xs);
710
+ padding: var(--cp-spacing-sm) var(--cp-spacing-md);
711
+ cursor: pointer;
712
+ user-select: none;
713
+ color: var(--cp-text-tertiary);
714
+ font-size: var(--cp-font-size-sm);
715
+ letter-spacing: 0.04em;
716
+ transition: color 0.2s ease, background 0.2s ease;
717
+
718
+ &:hover {
719
+ color: var(--cp-card-color, var(--cp-text-primary));
720
+ background: color-mix(in srgb, var(--cp-card-color, var(--cp-text-primary)) 8%, transparent);
721
+ }
722
+ }
723
+
724
+ @include e(collapse-action-text) {
725
+ line-height: 1;
726
+ }
727
+
728
+ @include e(collapse-action-icon) {
729
+ font-size: 10px;
730
+ line-height: 1;
731
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
732
+
733
+ &.is-expanded {
734
+ transform: rotate(180deg);
735
+ }
736
+ }
737
+
738
+ // ===== 加载遮罩 (Loading Overlay) =====
739
+ @include e(loading-overlay) {
740
+ position: absolute;
741
+ inset: 0;
742
+ z-index: 12;
743
+ display: flex;
744
+ flex-direction: column;
745
+ align-items: center;
746
+ justify-content: center;
747
+ gap: var(--cp-spacing-sm);
748
+ background: var(--cp-card-loading-bg, rgba(10, 10, 18, 0.75));
749
+ backdrop-filter: var(--cp-card-loading-backdrop, blur(4px));
750
+ pointer-events: auto;
751
+ }
752
+
753
+ @include e(loading-text) {
754
+ font-size: var(--cp-font-size-sm);
755
+ color: var(--cp-card-loading-text-color, var(--cp-text-secondary));
756
+ letter-spacing: 0.05em;
757
+ user-select: none;
758
+ margin-top: var(--cp-spacing-xs);
759
+ }
760
+
761
+ // ===== 加载遮罩过渡动画 =====
762
+ .cp-card-loading-enter-active,
763
+ .cp-card-loading-leave-active {
764
+ transition: opacity 0.3s ease;
765
+ }
766
+ .cp-card-loading-enter-from,
767
+ .cp-card-loading-leave-to {
768
+ opacity: 0;
769
+ }
770
+
771
+ // ===== 加载状态 (Loading) =====
772
+ @include when(loading) {
773
+ // loading 时仍可悬停查看效果,但内容被遮罩阻挡
774
+ > .cp-card__container {
775
+ // container 需要 position: relative 来定位 loading overlay
776
+ position: relative;
777
+ }
778
+ }
779
+
780
+ // ===== 禁用状态 (Disabled) =====
781
+ @include when(disabled) {
782
+ pointer-events: none;
783
+ cursor: not-allowed;
784
+
785
+ > .cp-card__container {
786
+ opacity: 0.5;
787
+ filter: grayscale(0.6);
788
+ }
789
+
790
+ // 加载遮罩也必须禁止 pointer-events,
791
+ // 否则子元素 pointer-events: auto 会让 :hover 冒泡到卡片根节点
792
+ .cp-card__loading-overlay {
793
+ pointer-events: none !important;
794
+ }
795
+
796
+ // 装饰块始终保持低透明度
797
+ &::after {
798
+ opacity: 0.2 !important;
799
+ }
800
+
801
+ // 彻底禁止所有 hover 视觉反馈
802
+ &:hover {
803
+ // 阻止阴影 hover
804
+ filter: none !important;
805
+ box-shadow: none !important;
806
+ // 阻止 hover-scale
807
+ transform: none !important;
808
+
809
+ // 装饰块不变亮
810
+ &::after {
811
+ opacity: 0.2 !important;
812
+ }
813
+
814
+ // 容器不响应 hover
815
+ > .cp-card__container {
816
+ border-color: inherit;
817
+ box-shadow: none !important;
818
+ filter: grayscale(0.6) !important;
819
+ }
820
+
821
+ // 覆层不弹出
822
+ .cp-card__overlay-backdrop {
823
+ opacity: 0 !important;
824
+ }
825
+ .cp-card__overlay {
826
+ opacity: 0 !important;
827
+ pointer-events: none !important;
828
+ transform: none !important;
829
+ }
830
+ }
831
+ }
832
+ }