@robot-admin/layout 2.0.2 → 2.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,662 @@
1
+ /**
2
+ * @robot-admin/layout
3
+ *
4
+ * 布局全局样式 - 所有布局共享的基础样式
5
+ * 包含:布局容器、内容区、主题适配、侧边栏基础、菜单毛玻璃效果、折叠菜单、过渡动画
6
+ *
7
+ * CSS 变量依赖(消费方需定义):
8
+ * --app-bg-body : 页面背景色
9
+ * --app-bg-content : 内容区背景色
10
+ * --app-bg-surface : 卡片/面板背景色
11
+ * --app-menu-bg : 菜单背景色
12
+ * --app-text-primary : 主文字色
13
+ * --app-text-secondary: 次文字色
14
+ * --app-border-color : 边框色
15
+ * --primary-color : 主题色
16
+ */
17
+
18
+ // ==================== 基础布局样式 ====================
19
+ .layout-container {
20
+ height: 100vh;
21
+ overflow: hidden;
22
+ display: flex;
23
+ flex-direction: column;
24
+ }
25
+
26
+ // ==================== 内容区域样式 ====================
27
+ .layout-container .content-with-header {
28
+ margin-top: 100px;
29
+ height: calc(100vh - 150px);
30
+ }
31
+
32
+ .layout-container .app-content {
33
+ background-color: var(--app-bg-content);
34
+ }
35
+
36
+ .layout-container .n-layout-content {
37
+ display: flex;
38
+ flex-direction: column;
39
+ flex: 1;
40
+ overflow-x: hidden;
41
+ }
42
+
43
+ .main-content {
44
+ flex: 1;
45
+ padding: 16px;
46
+ overflow-y: auto;
47
+ overflow-x: hidden;
48
+ width: 100%;
49
+ border-radius: 8px;
50
+ }
51
+
52
+ // ==================== 主题相关样式 ====================
53
+ [data-theme='light'] .layout-container .light-theme,
54
+ .layout-container .light-theme {
55
+ background-color: var(--app-bg-body);
56
+ }
57
+
58
+ [data-theme='dark'] .layout-container .dark-theme,
59
+ .layout-container .dark-theme {
60
+ background-color: var(--app-bg-body);
61
+ }
62
+
63
+ .layout-container.light-mode .n-layout .n-layout-scroll-container {
64
+ background-color: var(--app-bg-surface);
65
+ border-radius: 10px;
66
+ }
67
+
68
+ .layout-container.dark-mode .n-layout .n-layout-scroll-container,
69
+ .layout-container.system-mode .n-layout .n-layout-scroll-container {
70
+ background-color: var(--app-bg-surface);
71
+ }
72
+
73
+ // ==================== 侧边栏和菜单样式 ====================
74
+ .layout-sider {
75
+ transform: translateZ(0);
76
+ backface-visibility: hidden;
77
+ contain: layout style paint;
78
+ }
79
+
80
+ .layout-sider.light-theme {
81
+ background-color: var(--app-menu-bg);
82
+ }
83
+
84
+ .layout-sider.dark-theme {
85
+ background-color: var(--app-menu-bg);
86
+ }
87
+
88
+ .layout-sider .n-scrollbar-rail {
89
+ width: 0 !important;
90
+ }
91
+
92
+ .layout-sider .n-scrollbar-content {
93
+ padding-right: 0 !important;
94
+ }
95
+
96
+ .layout-container .n-layout-sider {
97
+ flex-shrink: 0;
98
+ height: 100%;
99
+ display: flex;
100
+ flex-direction: column;
101
+ overflow: hidden;
102
+ }
103
+
104
+ .menu-scroll-container {
105
+ height: calc(100vh - 56px);
106
+ overflow-y: scroll;
107
+ scrollbar-width: none;
108
+ -ms-overflow-style: none;
109
+ flex: 1;
110
+ display: flex;
111
+ flex-direction: column;
112
+ }
113
+
114
+ .menu-scroll-container::-webkit-scrollbar {
115
+ display: none;
116
+ }
117
+
118
+ .layout-container .n-menu.n-menu--vertical {
119
+ flex: 1;
120
+ min-height: min-content;
121
+ overflow-y: auto;
122
+ overflow-x: hidden;
123
+ }
124
+
125
+ // ==================== 菜单图标和文字样式 ====================
126
+ .layout-container .n-menu-item-content__icon {
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ vertical-align: middle;
131
+ width: 18px !important;
132
+ height: 18px !important;
133
+ margin-right: 10px;
134
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
135
+ font-size: 18px !important;
136
+ }
137
+
138
+ .layout-container .n-menu-item-content__icon .n-icon {
139
+ width: 18px !important;
140
+ height: 18px !important;
141
+ font-size: 18px !important;
142
+ }
143
+
144
+ .layout-container .n-menu-item-content__icon svg {
145
+ width: 18px !important;
146
+ height: 18px !important;
147
+ }
148
+
149
+ .layout-container .n-menu-item-content-header {
150
+ font-size: 14px;
151
+ font-weight: 500;
152
+ letter-spacing: 0.2px;
153
+ line-height: 1.5;
154
+ }
155
+
156
+ .layout-container .n-menu-item-content__arrow {
157
+ font-size: 14px;
158
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
159
+ }
160
+
161
+ // ==================== 🎨 毛玻璃质感菜单效果(性能优化版)====================
162
+
163
+ /* 菜单项基础样式 - 卡片质感默认状态 */
164
+ .layout-container .n-menu-item {
165
+ border-radius: 0;
166
+ position: relative;
167
+ overflow: visible;
168
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
169
+ will-change: transform;
170
+
171
+ &::before {
172
+ content: '';
173
+ position: absolute;
174
+ top: 0;
175
+ left: 0;
176
+ right: 0;
177
+ bottom: 0;
178
+ background: linear-gradient(135deg,
179
+ rgba(255, 255, 255, 0.08) 0%,
180
+ rgba(255, 255, 255, 0.04) 100%);
181
+ border-radius: 8px;
182
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
183
+ z-index: -1;
184
+ box-shadow:
185
+ 0 2px 4px rgba(0, 0, 0, 0.08),
186
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
187
+ }
188
+ }
189
+
190
+ /* 菜单项内容容器 - 卡片质感 */
191
+ .layout-container .n-menu-item-content {
192
+ border-radius: 8px;
193
+ background: transparent;
194
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
195
+ position: relative;
196
+ padding: 10px 16px;
197
+
198
+ &::after {
199
+ content: '';
200
+ position: absolute;
201
+ top: 0;
202
+ left: 0;
203
+ right: 0;
204
+ bottom: 0;
205
+ border: 1px solid rgba(255, 255, 255, 0.06);
206
+ border-left: 2px solid transparent;
207
+ border-radius: 8px;
208
+ pointer-events: none;
209
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
210
+ }
211
+ }
212
+
213
+ /* Hover 状态 - 增强卡片效果 */
214
+ .layout-container .n-menu-item:hover {
215
+ transform: translateX(2px);
216
+
217
+ &::before {
218
+ background: rgba(255, 255, 255, 0.1);
219
+ border-radius: 8px;
220
+ box-shadow:
221
+ 0 4px 16px rgba(0, 0, 0, 0.12),
222
+ inset 0 1px 0 rgba(255, 255, 255, 0.12);
223
+ }
224
+ }
225
+
226
+ .layout-container .n-menu-item:hover .n-menu-item-content {
227
+ backdrop-filter: blur(12px);
228
+ -webkit-backdrop-filter: blur(12px);
229
+ border-radius: 8px;
230
+
231
+ &::after {
232
+ border-left-color: rgba(99, 102, 241, 0.4);
233
+ border-radius: 8px;
234
+ box-shadow:
235
+ 0 0 15px rgba(99, 102, 241, 0.15),
236
+ inset 0 1px 1px rgba(255, 255, 255, 0.1);
237
+ }
238
+ }
239
+
240
+ .layout-container .n-menu-item:hover .n-menu-item-content__icon {
241
+ transform: scale(1.08);
242
+ color: var(--n-item-icon-color-active-hover);
243
+ }
244
+
245
+ /* Active/选中状态 - 高级卡片激活效果 */
246
+ .layout-container .n-menu-item--selected,
247
+ .layout-container .n-menu-item-content--selected {
248
+ &::before {
249
+ background: linear-gradient(90deg,
250
+ rgba(99, 102, 241, 0.18) 0%,
251
+ rgba(139, 92, 246, 0.12) 100%);
252
+ border-radius: 8px;
253
+ box-shadow:
254
+ 0 3px 12px rgba(99, 102, 241, 0.25),
255
+ inset 0 1px 0 rgba(99, 102, 241, 0.2);
256
+ }
257
+ }
258
+
259
+ .layout-container .n-menu-item--selected .n-menu-item-content,
260
+ .layout-container .n-menu-item-content--selected {
261
+ backdrop-filter: blur(14px) saturate(130%);
262
+ -webkit-backdrop-filter: blur(14px) saturate(130%);
263
+
264
+ &::after {
265
+ border-left: 3px solid rgba(99, 102, 241, 0.8);
266
+ box-shadow:
267
+ 0 0 20px rgba(99, 102, 241, 0.25),
268
+ inset 0 1px 1px rgba(255, 255, 255, 0.15);
269
+ }
270
+ }
271
+
272
+ .layout-container .n-menu-item--selected .n-menu-item-content__icon {
273
+ filter: drop-shadow(0 0 6px rgba(99, 102, 241, 0.5));
274
+ transform: scale(1.05);
275
+ color: var(--n-item-icon-color-active);
276
+ }
277
+
278
+ /* Active 按下状态 */
279
+ .layout-container .n-menu-item:active {
280
+ transform: scale(0.98);
281
+ }
282
+
283
+ /* 子菜单父项样式 */
284
+ .layout-container .n-menu-item-content--child-active {
285
+ &::before {
286
+ background: rgba(99, 102, 241, 0.1);
287
+ box-shadow:
288
+ 0 2px 12px rgba(99, 102, 241, 0.12),
289
+ inset 0 1px 0 rgba(255, 255, 255, 0.08);
290
+ }
291
+
292
+ &::after {
293
+ border-left: 2px solid rgba(99, 102, 241, 0.5);
294
+ }
295
+
296
+ backdrop-filter: blur(10px);
297
+ -webkit-backdrop-filter: blur(10px);
298
+ }
299
+
300
+ /* 一级菜单项对齐 */
301
+ .layout-container .n-menu > .n-menu-item,
302
+ .layout-container .n-menu > .n-submenu {
303
+ margin: 4px 12px;
304
+ }
305
+
306
+ /* 二级及以下菜单项 */
307
+ .layout-container .n-submenu-children .n-menu-item {
308
+ margin: 4px 0;
309
+ }
310
+
311
+ .layout-container .n-submenu-children .n-menu-item-content {
312
+ padding-left: 46px;
313
+ }
314
+
315
+ // ==================== 主题优化 ====================
316
+ .dark-theme {
317
+ color-scheme: dark;
318
+
319
+ .layout-container .n-menu-item::before {
320
+ background: linear-gradient(135deg,
321
+ rgba(255, 255, 255, 0.08) 0%,
322
+ rgba(255, 255, 255, 0.04) 100%);
323
+ box-shadow:
324
+ 0 2px 4px rgba(0, 0, 0, 0.12),
325
+ inset 0 1px 0 rgba(255, 255, 255, 0.08);
326
+ }
327
+
328
+ .layout-container .n-menu-item:hover::before {
329
+ background: linear-gradient(135deg,
330
+ rgba(255, 255, 255, 0.12) 0%,
331
+ rgba(255, 255, 255, 0.08) 100%);
332
+ }
333
+ }
334
+
335
+ .light-theme {
336
+ color-scheme: light;
337
+
338
+ .layout-container .n-menu-item::before {
339
+ background: linear-gradient(135deg,
340
+ rgba(255, 255, 255, 0.6) 0%,
341
+ rgba(255, 255, 255, 0.4) 100%);
342
+ box-shadow:
343
+ 0 2px 4px rgba(0, 0, 0, 0.04),
344
+ inset 0 1px 0 rgba(255, 255, 255, 0.8);
345
+ }
346
+
347
+ .layout-container .n-menu-item:hover::before {
348
+ background: linear-gradient(135deg,
349
+ rgba(255, 255, 255, 0.8) 0%,
350
+ rgba(255, 255, 255, 0.6) 100%);
351
+ }
352
+
353
+ .layout-container .n-menu-item-content::after {
354
+ border-color: rgba(0, 0, 0, 0.08);
355
+ }
356
+ }
357
+
358
+ // ==================== 折叠菜单样式 ====================
359
+ .layout-container .n-menu.n-menu--collapsed {
360
+ width: 64px !important;
361
+ display: flex;
362
+ flex-direction: column;
363
+ align-items: center;
364
+ }
365
+
366
+ .layout-container .n-menu.n-menu--collapsed .n-menu-item-content {
367
+ justify-content: center !important;
368
+ padding: 0 !important;
369
+ display: flex;
370
+ align-items: center;
371
+ width: 62px;
372
+ }
373
+
374
+ .layout-container .n-menu.n-menu--collapsed .n-icon {
375
+ margin-left: 40px !important;
376
+ margin-top: 4px !important;
377
+ }
378
+
379
+ .layout-container .n-menu.n-menu--collapsed .n-menu-item {
380
+ padding: 0 !important;
381
+ display: flex;
382
+ justify-content: center;
383
+ width: 100%;
384
+ }
385
+
386
+ .layout-container .n-menu.n-menu--collapsed .n-menu-item-content-header {
387
+ margin: 0 auto;
388
+ margin-top: -10px;
389
+ padding: 0;
390
+ }
391
+
392
+ .layout-container .n-menu.n-menu--collapsed .n-menu-item-content__icon {
393
+ margin-right: 0;
394
+ }
395
+
396
+ .layout-container
397
+ .n-menu.n-menu--collapsed
398
+ .n-menu-item-content--child-active
399
+ .n-menu-item-content__icon
400
+ {
401
+ color: var(--n-item-color-active) !important;
402
+ }
403
+
404
+ /* 折叠菜单选中状态 - 毛玻璃效果 */
405
+ .layout-container .n-menu.n-menu--collapsed .n-menu-item-content--child-active {
406
+ &::before {
407
+ background: linear-gradient(135deg,
408
+ rgba(99, 102, 241, 0.25) 0%,
409
+ rgba(139, 92, 246, 0.2) 100%);
410
+ border-radius: 10px;
411
+ box-shadow:
412
+ 0 8px 24px rgba(99, 102, 241, 0.3),
413
+ inset 0 1px 1px rgba(255, 255, 255, 0.2);
414
+ }
415
+
416
+ backdrop-filter: blur(16px) saturate(150%);
417
+ -webkit-backdrop-filter: blur(16px) saturate(150%);
418
+
419
+ &::after {
420
+ box-shadow: 0 0 20px rgba(99, 102, 241, 0.4);
421
+ }
422
+ }
423
+
424
+ /* 折叠菜单 Hover 效果 */
425
+ .layout-container .n-menu.n-menu--collapsed .n-menu-item:hover {
426
+ transform: scale(1.05);
427
+
428
+ &::before {
429
+ background: rgba(255, 255, 255, 0.1);
430
+ box-shadow:
431
+ 0 4px 16px rgba(0, 0, 0, 0.15),
432
+ inset 0 1px 0 rgba(255, 255, 255, 0.15);
433
+ }
434
+ }
435
+
436
+ /* 折叠菜单图标颜色 */
437
+ .n-menu--collapsed .n-menu-item-content__icon {
438
+ color: rgba(229, 231, 235, 0.9) !important;
439
+ }
440
+
441
+ // ==================== 其他辅助样式 ====================
442
+ .layout-container .n-layout {
443
+ width: 100%;
444
+ min-width: 0;
445
+ }
446
+
447
+ .no-horizontal-scroll {
448
+ overflow-x: hidden !important;
449
+ }
450
+
451
+ // ==================== 子菜单和菜单组毛玻璃效果 ====================
452
+ .layout-container .n-submenu {
453
+ margin: 4px 0;
454
+ }
455
+
456
+ .layout-container .n-submenu > .n-menu-item-content {
457
+ padding: 10px 16px;
458
+ }
459
+
460
+ .layout-container .n-submenu-children .n-menu-item {
461
+ margin: 2px 0;
462
+ position: relative;
463
+
464
+ &::before {
465
+ content: none;
466
+ }
467
+ }
468
+
469
+ .layout-container .n-submenu-children .n-menu-item-content {
470
+ padding: 8px 16px 8px 46px;
471
+ font-size: 13px;
472
+ }
473
+
474
+ .layout-container .n-submenu-children .n-menu-item-content__icon {
475
+ width: 16px !important;
476
+ height: 16px !important;
477
+ font-size: 16px !important;
478
+ margin-right: 8px;
479
+ }
480
+
481
+ .layout-container .n-submenu-children .n-menu-item-content__icon .n-icon {
482
+ width: 16px !important;
483
+ height: 16px !important;
484
+ font-size: 16px !important;
485
+ }
486
+
487
+ .layout-container .n-submenu-children .n-menu-item-content__icon svg {
488
+ width: 16px !important;
489
+ height: 16px !important;
490
+ }
491
+
492
+ .layout-container .n-submenu-children .n-menu-item:hover {
493
+ transform: translateX(2px);
494
+ }
495
+
496
+ .layout-container .n-submenu-children {
497
+ background: rgba(0, 0, 0, 0.05);
498
+ backdrop-filter: blur(6px);
499
+ -webkit-backdrop-filter: blur(6px);
500
+ margin: 2px 0;
501
+ padding: 4px 0;
502
+ border-left: 2px solid rgba(99, 102, 241, 0.3);
503
+ }
504
+
505
+ /* 菜单组标题 */
506
+ .layout-container .n-menu-item-group-title {
507
+ font-size: 11px;
508
+ font-weight: 600;
509
+ text-transform: uppercase;
510
+ letter-spacing: 1.2px;
511
+ padding: 12px 16px 6px;
512
+ opacity: 0.5;
513
+ position: relative;
514
+
515
+ &::after {
516
+ content: '';
517
+ position: absolute;
518
+ bottom: 0;
519
+ left: 16px;
520
+ right: 16px;
521
+ height: 1px;
522
+ background: linear-gradient(to right,
523
+ transparent,
524
+ rgba(99, 102, 241, 0.2),
525
+ transparent);
526
+ }
527
+ }
528
+
529
+ /* 菜单分割线 */
530
+ .layout-container .n-menu-divider {
531
+ margin: 8px 16px;
532
+ height: 1px;
533
+ background: linear-gradient(to right,
534
+ transparent,
535
+ rgba(255, 255, 255, 0.1),
536
+ transparent);
537
+ backdrop-filter: blur(4px);
538
+ -webkit-backdrop-filter: blur(4px);
539
+ }
540
+
541
+ /* 加载状态优化 */
542
+ .layout-container .n-menu-item.n-menu-item--loading {
543
+ &::before {
544
+ background: linear-gradient(90deg,
545
+ rgba(99, 102, 241, 0.1) 0%,
546
+ rgba(139, 92, 246, 0.2) 50%,
547
+ rgba(99, 102, 241, 0.1) 100%);
548
+ background-size: 200% 100%;
549
+ animation: shimmer 2s infinite;
550
+ }
551
+ }
552
+
553
+ @keyframes shimmer {
554
+ 0% {
555
+ background-position: -200% 0;
556
+ }
557
+ 100% {
558
+ background-position: 200% 0;
559
+ }
560
+ }
561
+
562
+ /* 禁用状态 */
563
+ .layout-container .n-menu-item.n-menu-item--disabled {
564
+ opacity: 0.4;
565
+ filter: grayscale(0.5);
566
+ cursor: not-allowed;
567
+
568
+ &::before {
569
+ background: rgba(255, 255, 255, 0.01);
570
+ }
571
+
572
+ &:hover {
573
+ transform: none;
574
+ }
575
+ }
576
+
577
+ // ==================== ⚡ 页面切换过渡动画 ====================
578
+
579
+ // 滑动效果
580
+ .fade-slide-enter-active,
581
+ .fade-slide-leave-active {
582
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
583
+ }
584
+
585
+ .fade-slide-enter-from {
586
+ opacity: 0;
587
+ transform: translateX(20px);
588
+ }
589
+
590
+ .fade-slide-leave-to {
591
+ opacity: 0;
592
+ transform: translateX(-20px);
593
+ }
594
+
595
+ // 淡入效果
596
+ .fade-transform-enter-active,
597
+ .fade-transform-leave-active {
598
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
599
+ }
600
+
601
+ .fade-transform-enter-from {
602
+ opacity: 0;
603
+ transform: scale(0.95);
604
+ }
605
+
606
+ .fade-transform-leave-to {
607
+ opacity: 0;
608
+ transform: scale(1.05);
609
+ }
610
+
611
+ // 缩放效果
612
+ .fade-zoom-enter-active,
613
+ .fade-zoom-leave-active {
614
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
615
+ }
616
+
617
+ .fade-zoom-enter-from {
618
+ opacity: 0;
619
+ transform: scale(0.8);
620
+ }
621
+
622
+ .fade-zoom-leave-to {
623
+ opacity: 0;
624
+ transform: scale(0.8);
625
+ }
626
+
627
+ // ==================== 🎨 布局开发中提示样式 ====================
628
+
629
+ .layout-coming-soon {
630
+ display: flex;
631
+ align-items: center;
632
+ justify-content: center;
633
+ height: 100vh;
634
+ background-color: var(--app-bg-content);
635
+ }
636
+
637
+ .coming-soon-content {
638
+ text-align: center;
639
+ max-width: 400px;
640
+ padding: 40px;
641
+ border-radius: 12px;
642
+ background-color: var(--app-bg-surface);
643
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
644
+ }
645
+
646
+ .coming-soon-icon {
647
+ font-size: 64px;
648
+ margin-bottom: 16px;
649
+ }
650
+
651
+ .coming-soon-title {
652
+ font-size: 24px;
653
+ font-weight: 600;
654
+ margin-bottom: 8px;
655
+ color: var(--app-text-primary);
656
+ }
657
+
658
+ .coming-soon-desc {
659
+ font-size: 16px;
660
+ color: var(--app-text-secondary);
661
+ line-height: 1.5;
662
+ }