@cyberpunk-vue/theme-chalk 1.14.0 → 1.14.2

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