@cyberpunk-vue/theme-chalk 0.1.0

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.
@@ -0,0 +1,631 @@
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
+ --cp-card-shadow-color: rgba(0, 0, 0, 0.4);
13
+ // 统一定义 clip-path 路径,方便伪元素(阴影层)同步使用
14
+ --cp-card-clip-path: polygon(12px 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%, 0 12px);
15
+
16
+ position: relative;
17
+ display: flex;
18
+ flex-direction: column;
19
+ transition: all var(--cp-card-dimmed-duration, 0.3s) ease;
20
+ // 移除 overflow: hidden,以便展示外部阴影
21
+
22
+ @include e(container) {
23
+ position: relative;
24
+ display: flex;
25
+ flex-direction: column;
26
+ flex: 1;
27
+ background: var(--cp-card-bg);
28
+ border: 1px solid var(--cp-card-border-color, var(--cp-border));
29
+ color: var(--cp-text-primary);
30
+ transition: all var(--cp-card-dimmed-duration, 0.3s) ease, filter 0.4s ease, opacity 0.4s ease;
31
+ width: 100%;
32
+ height: 100%;
33
+ // 隐藏溢出内容,防止覆层动画影响页面布局
34
+ overflow: hidden;
35
+ // 强制开启硬件加速,修复 backdrop-filter + clip-path 渲染问题
36
+ transform: translateZ(0);
37
+ backface-visibility: hidden;
38
+ will-change: clip-path, filter;
39
+
40
+ // 同时保留基础裁剪,防止闪烁
41
+ clip-path: var(--cp-card-clip-path);
42
+ }
43
+
44
+ // 类型变体控制颜色变量
45
+ @each $type in (primary, success, warning, error, info) {
46
+ &.cp-card--#{$type} {
47
+ --cp-card-color: var(--cp-color-#{$type});
48
+ --cp-card-color-light: var(--cp-color-#{$type}-light);
49
+ }
50
+ }
51
+
52
+ // 强制开启隔离层,确保内部 clip-path + backdrop-filter 渲染稳定
53
+ isolation: isolate;
54
+
55
+ // 阴影辅助层 (伪元素),用于解决 Semi 模式下 backdrop-filter 与 drop-shadow 的冲突,以及 box-shadow 无法跟随 clip 的问题
56
+ // 默认隐藏,由变体激活
57
+ &::before {
58
+ content: '';
59
+ position: absolute;
60
+ inset: 0;
61
+ z-index: -1;
62
+ background: var(--cp-card-shadow-color);
63
+ // 默认透明度0,用于渐变出现
64
+ opacity: 0;
65
+ transition: opacity 0.3s ease;
66
+ pointer-events: none;
67
+ display: none; // 默认不渲染,仅在需要的变体中开启
68
+ }
69
+
70
+ // 装饰性小方块 (右上角)
71
+ &::after {
72
+ content: '';
73
+ position: absolute;
74
+ top: 0;
75
+ right: 0;
76
+ width: 10px;
77
+ height: 10px;
78
+ background: var(--cp-card-color);
79
+ opacity: 0.4;
80
+ z-index: 2;
81
+ transition: all 0.3s ease;
82
+ }
83
+
84
+ // 悬停效果
85
+ &:hover {
86
+ &::after {
87
+ opacity: 1;
88
+ }
89
+ }
90
+
91
+ // ===== 变体 =====
92
+ // ===== 变体 =====
93
+ @include m(solid) {
94
+ .cp-card__container {
95
+ background: var(--cp-card-bg);
96
+ border-color: var(--cp-border);
97
+
98
+ // 顶部装饰线 + 渐变背光
99
+ &::before {
100
+ content: '';
101
+ position: absolute;
102
+ top: 0;
103
+ left: 0;
104
+ width: 100%;
105
+ height: 48px;
106
+ // 2px 的实色顶线 + 渐变背景
107
+ background: linear-gradient(to bottom, var(--cp-card-color) 2px, var(--cp-card-color-light) 2px, transparent 100%);
108
+ opacity: 0;
109
+ transition: opacity 0.3s ease;
110
+ pointer-events: none;
111
+ z-index: 1;
112
+ }
113
+ }
114
+
115
+ &.cp-card--primary,
116
+ &.cp-card--success,
117
+ &.cp-card--warning,
118
+ &.cp-card--error,
119
+ &.cp-card--info {
120
+ .cp-card__container::before {
121
+ opacity: 0.8;
122
+ }
123
+ }
124
+
125
+ // 自定义 color 也要显示线条
126
+ &[style*='--cp-card-color'] {
127
+ .cp-card__container::before {
128
+ opacity: 0.8;
129
+ }
130
+ }
131
+ }
132
+
133
+ @include m(outline) {
134
+ .cp-card__container {
135
+ background: transparent;
136
+ border-color: var(--cp-card-color);
137
+
138
+ &:hover {
139
+ border-color: var(--cp-card-color);
140
+ box-shadow: 0 0 10px var(--cp-card-color-light);
141
+ }
142
+ }
143
+
144
+ &.cp-card--default {
145
+ .cp-card__container {
146
+ border-color: var(--cp-border);
147
+ }
148
+ }
149
+ }
150
+
151
+ @include m(semi) {
152
+ // 使用变量控制背景,方便减淡模式统一覆盖
153
+ --cp-card-bg: rgba(42, 42, 58, 0.5);
154
+ --cp-card-bg-hover: rgba(42, 42, 58, 0.7);
155
+ --cp-card-border: var(--cp-border);
156
+
157
+ .cp-card__container {
158
+ background: var(--cp-card-bg);
159
+ backdrop-filter: blur(10px);
160
+ border-color: var(--cp-card-border);
161
+
162
+ &:hover {
163
+ background: var(--cp-card-bg-hover);
164
+ box-shadow: 0 0 15px var(--cp-card-color-light);
165
+ }
166
+ }
167
+
168
+ // 类型色状态下的变量覆盖
169
+ &.cp-card--primary,
170
+ &.cp-card--success,
171
+ &.cp-card--warning,
172
+ &.cp-card--error,
173
+ &.cp-card--info {
174
+ --cp-card-bg: color-mix(in srgb, var(--cp-bg-elevated) 85%, var(--cp-card-color));
175
+ --cp-card-bg-hover: color-mix(in srgb, var(--cp-bg-elevated) 75%, var(--cp-card-color));
176
+ --cp-card-border: var(--cp-card-color-light);
177
+ }
178
+ }
179
+
180
+ @include m(ghost) {
181
+ .cp-card__container {
182
+ background: transparent;
183
+ border-color: transparent;
184
+
185
+ &:hover {
186
+ background: var(--cp-bg-elevated);
187
+ border-color: var(--cp-card-color-light);
188
+ }
189
+ }
190
+
191
+ // 当 ghost 配合 themed 模式时,应用主题色分割线
192
+ &.cp-card--primary,
193
+ &.cp-card--success,
194
+ &.cp-card--warning,
195
+ &.cp-card--error,
196
+ &.cp-card--info {
197
+ --cp-card-divider-color: var(--cp-card-color-light);
198
+ }
199
+
200
+ // 自定义 color 也要显示主题色分割线
201
+ &[style*='--cp-card-color'] {
202
+ --cp-card-divider-color: var(--cp-card-color-light);
203
+ }
204
+
205
+ &::after {
206
+ display: none;
207
+ }
208
+ }
209
+
210
+ // ===== 形状模式 =====
211
+ @include m(shape-clip) {
212
+ .cp-card__container {
213
+ clip-path: var(--cp-card-clip-path);
214
+ }
215
+ // 同步形状给阴影层
216
+ &::before {
217
+ clip-path: var(--cp-card-clip-path);
218
+ }
219
+ }
220
+
221
+ @include m(shape-no-clip) {
222
+ .cp-card__container {
223
+ clip-path: none;
224
+ border-radius: 0;
225
+ overflow: hidden;
226
+ }
227
+
228
+ &::before {
229
+ clip-path: none;
230
+ border-radius: 0;
231
+ }
232
+
233
+ &::after {
234
+ display: none;
235
+ }
236
+ }
237
+
238
+ @include m(shape-round) {
239
+ .cp-card__container {
240
+ clip-path: none;
241
+ border-radius: var(--cp-radius-lg);
242
+ overflow: hidden;
243
+ }
244
+
245
+ &::before {
246
+ clip-path: none;
247
+ border-radius: var(--cp-radius-lg);
248
+ }
249
+
250
+ &::after {
251
+ display: none;
252
+ }
253
+ }
254
+
255
+ // ===== 阴影 =====
256
+ // 注意:clip-path 会裁剪 box-shadow,需要使用 filter: drop-shadow
257
+ @include m(shadow-always) {
258
+ filter: drop-shadow(0 4px 12px var(--cp-card-shadow-color));
259
+ }
260
+
261
+ @include m(shadow-hover) {
262
+ // 初始状态颜色与 hover 态一致,利用 0 偏移和 0 模糊被元素遮挡的特性隐藏
263
+ // 这样在过渡时颜色始终保持一致,不会出现黑色中间态
264
+ filter: drop-shadow(0 0 0 var(--cp-card-shadow-color));
265
+ transition: filter 0.3s ease;
266
+
267
+ &:hover {
268
+ filter: drop-shadow(0 4px 12px var(--cp-card-shadow-color));
269
+ }
270
+ }
271
+
272
+ @include m(shadow-never) {
273
+ filter: none;
274
+ box-shadow: none;
275
+ }
276
+
277
+ // 非切角模式可以使用 box-shadow(更平滑)
278
+ &.cp-card--shape-no-clip,
279
+ &.cp-card--shape-round {
280
+ &.cp-card--shadow-always {
281
+ filter: none;
282
+ box-shadow: 0 4px 20px var(--cp-card-shadow-color);
283
+ }
284
+
285
+ &.cp-card--shadow-hover {
286
+ filter: none;
287
+ // 利用负 spread 彻底隐藏阴影,且保持颜色一致
288
+ box-shadow: 0 0 0 -100px var(--cp-card-shadow-color);
289
+ transition: box-shadow 0.3s ease;
290
+
291
+ &:hover {
292
+ box-shadow: 0 4px 20px 0 var(--cp-card-shadow-color);
293
+ }
294
+ }
295
+ }
296
+
297
+ // Semi 变体特殊处理:禁用根部 filter,改用伪元素阴影层
298
+ // 原因:filter 与 backdrop-filter + clip-path 存在渲染冲突
299
+ &.cp-card--semi {
300
+ &.cp-card--shadow-always,
301
+ &.cp-card--shadow-hover {
302
+ filter: none !important;
303
+ }
304
+
305
+ // 启用伪元素阴影层
306
+ &.cp-card--shadow-always::before,
307
+ &.cp-card--shadow-hover::before {
308
+ display: block;
309
+ // 在伪元素上应用 filter,不会影响 container 的 backdrop-filter(因其是兄弟元素)
310
+ filter: drop-shadow(0 0 12px var(--cp-card-shadow-color));
311
+ }
312
+
313
+ // Always 模式:常驻显示
314
+ &.cp-card--shadow-always::before {
315
+ opacity: 1;
316
+ }
317
+
318
+ // Hover 模式:默认隐藏,hover 显示
319
+ &.cp-card--shadow-hover::before {
320
+ opacity: 0;
321
+ }
322
+ &.cp-card--shadow-hover:hover::before {
323
+ opacity: 1;
324
+ }
325
+
326
+ // 禁用之前的 hacky box-shadow
327
+ &.cp-card--shadow-always .cp-card__container,
328
+ &.cp-card--shadow-hover .cp-card__container,
329
+ &.cp-card--shadow-hover:hover .cp-card__container {
330
+ box-shadow: none !important;
331
+ }
332
+ }
333
+
334
+ // ===== 子元素 =====
335
+ @include e(cover) {
336
+ width: 100%;
337
+ overflow: hidden;
338
+ flex-shrink: 0;
339
+ border-bottom: 1px solid var(--cp-border);
340
+ background: #000;
341
+ line-height: 0; // 消除图片下方的间隙
342
+
343
+ img {
344
+ width: 100%;
345
+ height: auto;
346
+ display: block;
347
+ }
348
+ }
349
+
350
+ @include e(header) {
351
+ display: flex;
352
+ align-items: center;
353
+ justify-content: space-between;
354
+ padding: var(--cp-spacing-md) var(--cp-spacing-lg);
355
+ min-height: 48px;
356
+ transition: border-color var(--cp-card-dimmed-duration, 0.3s) ease;
357
+
358
+ &.is-bordered {
359
+ border-bottom: 1px solid var(--cp-card-header-divider-color, var(--cp-card-divider-color, var(--cp-border)));
360
+ }
361
+ }
362
+
363
+ @include e(title) {
364
+ font-family: 'Orbitron', 'Rajdhani', sans-serif;
365
+ font-weight: 600;
366
+ font-size: var(--cp-font-size-lg);
367
+ text-transform: uppercase;
368
+ letter-spacing: 0.05em;
369
+ color: var(--cp-text-primary);
370
+ }
371
+
372
+ @include e(extra) {
373
+ display: flex;
374
+ align-items: center;
375
+ gap: var(--cp-spacing-sm);
376
+ }
377
+
378
+ @include e(body) {
379
+ flex: 1;
380
+ padding: var(--cp-spacing-lg);
381
+ color: var(--cp-text-secondary);
382
+ line-height: 1.6;
383
+ }
384
+
385
+ @include e(footer) {
386
+ display: flex;
387
+ align-items: center;
388
+ justify-content: flex-end;
389
+ padding: var(--cp-spacing-md) var(--cp-spacing-lg);
390
+ gap: var(--cp-spacing-sm);
391
+ transition: border-color var(--cp-card-dimmed-duration, 0.3s) ease;
392
+
393
+ &.is-bordered {
394
+ border-top: 1px solid var(--cp-card-footer-divider-color, var(--cp-card-divider-color, var(--cp-border)));
395
+ }
396
+ }
397
+
398
+ // ===== 覆层背景遮罩 (Overlay Backdrop) =====
399
+ // 覆盖整个卡片内容区域的效果层
400
+ @include e(overlay-backdrop) {
401
+ position: absolute;
402
+ inset: 0;
403
+ z-index: 9;
404
+ opacity: 0;
405
+ pointer-events: none;
406
+ transition-property: opacity, backdrop-filter, background;
407
+ transition-duration: var(--cp-card-overlay-duration, 300ms);
408
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
409
+
410
+ // ===== 效果类型 =====
411
+ // 无效果
412
+ &.cp-card__overlay-backdrop--effect-none {
413
+ background: transparent;
414
+ backdrop-filter: none;
415
+ }
416
+
417
+ // 仅毛玻璃
418
+ &.cp-card__overlay-backdrop--effect-blur {
419
+ background: transparent;
420
+ backdrop-filter: blur(var(--cp-card-overlay-blur, 10px));
421
+ }
422
+
423
+ // 仅颜色
424
+ &.cp-card__overlay-backdrop--effect-color {
425
+ background: var(--cp-card-overlay-color, rgba(26, 26, 36, 0.8));
426
+ backdrop-filter: none;
427
+ }
428
+
429
+ // 毛玻璃 + 颜色 (默认)
430
+ &.cp-card__overlay-backdrop--effect-blur-color {
431
+ background: var(--cp-card-overlay-color, rgba(26, 26, 36, 0.8));
432
+ backdrop-filter: blur(var(--cp-card-overlay-blur, 10px));
433
+ }
434
+ }
435
+
436
+ // ===== 覆层操作区 (Overlay Actions) =====
437
+ // 定位、动画和独立效果控制
438
+ @include e(overlay) {
439
+ position: absolute;
440
+ left: 0;
441
+ right: 0;
442
+ z-index: 10;
443
+ padding: var(--cp-spacing-md) var(--cp-spacing-lg);
444
+ border-top: 1px solid var(--cp-border);
445
+ opacity: 0;
446
+ pointer-events: none;
447
+ transition-property: opacity, transform, backdrop-filter, background;
448
+ transition-duration: var(--cp-card-overlay-duration, 300ms);
449
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
450
+
451
+ // ===== 操作区效果类型 =====
452
+ // 无效果
453
+ &.cp-card__overlay--effect-none {
454
+ background: transparent;
455
+ backdrop-filter: none;
456
+ }
457
+
458
+ // 仅毛玻璃
459
+ &.cp-card__overlay--effect-blur {
460
+ background: transparent;
461
+ backdrop-filter: blur(var(--cp-card-action-blur, 10px));
462
+ }
463
+
464
+ // 仅颜色
465
+ &.cp-card__overlay--effect-color {
466
+ background: var(--cp-card-action-color, rgba(26, 26, 36, 0.8));
467
+ backdrop-filter: none;
468
+ }
469
+
470
+ // 毛玻璃 + 颜色 (默认)
471
+ &.cp-card__overlay--effect-blur-color {
472
+ background: var(--cp-card-action-color, rgba(26, 26, 36, 0.8));
473
+ backdrop-filter: blur(var(--cp-card-action-blur, 10px));
474
+ }
475
+
476
+ // 位置: 底部 (默认)
477
+ &.cp-card__overlay--bottom {
478
+ bottom: 0;
479
+ }
480
+
481
+ // 位置: 顶部
482
+ &.cp-card__overlay--top {
483
+ top: 0;
484
+ border-top: none;
485
+ border-bottom: 1px solid var(--cp-border);
486
+ }
487
+
488
+ // 位置: 居中
489
+ &.cp-card__overlay--center {
490
+ top: 50%;
491
+ border-top: none;
492
+ border-bottom: none;
493
+ }
494
+
495
+ // 动画: 从底部滑入 (默认)
496
+ &.cp-card__overlay--slide-up {
497
+ transform: translateY(100%);
498
+ }
499
+
500
+ // 动画: 从顶部滑入
501
+ &.cp-card__overlay--slide-down {
502
+ transform: translateY(-100%);
503
+ }
504
+
505
+ // 动画: 从右侧滑入
506
+ &.cp-card__overlay--slide-left {
507
+ transform: translateX(100%);
508
+ }
509
+
510
+ // 动画: 从左侧滑入
511
+ &.cp-card__overlay--slide-right {
512
+ transform: translateX(-100%);
513
+ }
514
+
515
+ // 动画: 渐显
516
+ &.cp-card__overlay--fade {
517
+ transform: none;
518
+ }
519
+
520
+ // 动画: 缩放
521
+ &.cp-card__overlay--scale {
522
+ transform: scale(0.9);
523
+
524
+ // 居中位置时需要额外的 Y 偏移
525
+ &.cp-card__overlay--center {
526
+ transform: translateY(-50%) scale(0.9);
527
+ }
528
+ }
529
+ }
530
+
531
+ // Hover 显示覆层
532
+ &.is-has-overlay:hover {
533
+ .cp-card__overlay-backdrop {
534
+ opacity: 1;
535
+ }
536
+
537
+ .cp-card__overlay {
538
+ opacity: 1;
539
+ pointer-events: auto;
540
+ transform: translateY(0) translateX(0) scale(1);
541
+
542
+ // 居中位置需要保持 Y 居中
543
+ &.cp-card__overlay--center {
544
+ transform: translateY(-50%);
545
+ }
546
+ }
547
+ }
548
+
549
+ // ===== 减淡模式 (Dimmed Mode) =====
550
+ // 减淡模式:平常以无颜色的默认形态展示,hover 时显示真正的主题色
551
+ @include when(dimmed) {
552
+ // 平常状态:覆盖颜色变量为默认值
553
+ &:not(:hover) {
554
+ --cp-card-color: var(--cp-border);
555
+ --cp-card-color-light: rgba(255, 255, 255, 0.1);
556
+
557
+ // 针对 semi 变体,直接重置其背景变量
558
+ &.cp-card--semi {
559
+ --cp-card-bg: rgba(42, 42, 58, 0.5);
560
+ --cp-card-border: var(--cp-border);
561
+ }
562
+
563
+ &.cp-card--solid {
564
+ .cp-card__container::before {
565
+ opacity: 0 !important;
566
+ }
567
+ }
568
+
569
+ &.cp-card--outline {
570
+ .cp-card__container {
571
+ border-color: var(--cp-border);
572
+ }
573
+ }
574
+
575
+ // 重置 ghost 变体的分割线
576
+ &.cp-card--ghost {
577
+ --cp-card-divider-color: var(--cp-border);
578
+ }
579
+ }
580
+ }
581
+
582
+ // ===== Card Hover 触发 Image Hover =====
583
+ // 当开启 triggerImageHover 时,Card hover 会触发内部 CpImage 的 hover 效果
584
+ @include when(trigger-image-hover) {
585
+ &:hover {
586
+ // Scale 模式
587
+ .cp-image--hover-scale {
588
+ transform: scale(1.02);
589
+ box-shadow: 0 0 20px var(--cp-image-decor-color, var(--cp-color-primary-light));
590
+ filter: brightness(1.05);
591
+
592
+ .cp-image__decor {
593
+ background-color: var(--cp-image-decor-color, var(--cp-color-primary));
594
+ box-shadow: 0 0 8px var(--cp-image-decor-color, var(--cp-color-primary));
595
+ }
596
+ }
597
+
598
+ // Zoom 模式
599
+ .cp-image--hover-zoom {
600
+ box-shadow: 0 0 20px var(--cp-image-decor-color, var(--cp-color-primary-light));
601
+
602
+ .cp-image__inner {
603
+ transform: scale(1.1);
604
+ filter: brightness(1.05);
605
+ }
606
+
607
+ .cp-image__decor {
608
+ background-color: var(--cp-image-decor-color, var(--cp-color-primary));
609
+ box-shadow: 0 0 8px var(--cp-image-decor-color, var(--cp-color-primary));
610
+ }
611
+ }
612
+ }
613
+ }
614
+
615
+ // ===== Card Hover Scale =====
616
+ // 悬停时整卡放大效果
617
+ @include when(hover-scale) {
618
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
619
+ box-shadow 0.3s ease;
620
+
621
+ &:hover {
622
+ transform: scale(1.02);
623
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
624
+ }
625
+
626
+ &:active {
627
+ transform: scale(0.99);
628
+ }
629
+ }
630
+ }
631
+
@@ -0,0 +1,22 @@
1
+ // CpCheckboxGroup 组件样式
2
+
3
+ @use '../common/var' as *;
4
+ @use '../mixins/mixins' as *;
5
+
6
+ @include b(checkbox-group) {
7
+ display: inline-flex;
8
+ flex-wrap: wrap;
9
+ gap: 16px;
10
+
11
+ // 水平布局 (默认)
12
+ @include m(horizontal) {
13
+ flex-direction: row;
14
+ align-items: center;
15
+ }
16
+
17
+ // 垂直布局
18
+ @include m(vertical) {
19
+ flex-direction: column;
20
+ align-items: flex-start;
21
+ }
22
+ }