@zhang_jifan/fanui 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.
- package/ACCESSIBILITY.md +61 -0
- package/CHANGELOG.md +112 -0
- package/COMMERCIAL-LICENSE.md +71 -0
- package/DESIGN-SYSTEM.md +294 -0
- package/LICENSE +661 -0
- package/README.md +348 -0
- package/USAGE.md +1926 -0
- package/_index.scss +20 -0
- package/dist/fanui.cjs +15 -0
- package/dist/fanui.css +28209 -0
- package/dist/fanui.d.ts +353 -0
- package/dist/fanui.esm.js +71 -0
- package/dist/fanui.js +4782 -0
- package/dist/fanui.min.css +1 -0
- package/dist/fanui.mjs +71 -0
- package/dist/modules/fanui-advanced.css +830 -0
- package/dist/modules/fanui-advanced.min.css +129 -0
- package/dist/modules/fanui-alert.css +575 -0
- package/dist/modules/fanui-alert.min.css +122 -0
- package/dist/modules/fanui-badge.css +426 -0
- package/dist/modules/fanui-badge.min.css +77 -0
- package/dist/modules/fanui-base.css +1394 -0
- package/dist/modules/fanui-base.min.css +236 -0
- package/dist/modules/fanui-blog.css +762 -0
- package/dist/modules/fanui-blog.min.css +108 -0
- package/dist/modules/fanui-button.css +526 -0
- package/dist/modules/fanui-button.min.css +56 -0
- package/dist/modules/fanui-card.css +291 -0
- package/dist/modules/fanui-card.min.css +52 -0
- package/dist/modules/fanui-choice.css +539 -0
- package/dist/modules/fanui-choice.min.css +83 -0
- package/dist/modules/fanui-dashboard.css +1057 -0
- package/dist/modules/fanui-dashboard.min.css +160 -0
- package/dist/modules/fanui-data.css +687 -0
- package/dist/modules/fanui-data.min.css +125 -0
- package/dist/modules/fanui-feedback.css +432 -0
- package/dist/modules/fanui-feedback.min.css +79 -0
- package/dist/modules/fanui-form.css +779 -0
- package/dist/modules/fanui-form.min.css +123 -0
- package/dist/modules/fanui-glass.css +497 -0
- package/dist/modules/fanui-glass.min.css +46 -0
- package/dist/modules/fanui-input-plus.css +799 -0
- package/dist/modules/fanui-input-plus.min.css +124 -0
- package/dist/modules/fanui-interactive.css +960 -0
- package/dist/modules/fanui-interactive.min.css +138 -0
- package/dist/modules/fanui-layout.css +4399 -0
- package/dist/modules/fanui-layout.min.css +1172 -0
- package/dist/modules/fanui-marketing.css +1125 -0
- package/dist/modules/fanui-marketing.min.css +144 -0
- package/dist/modules/fanui-nav.css +458 -0
- package/dist/modules/fanui-nav.min.css +76 -0
- package/dist/modules/fanui-overlay.css +547 -0
- package/dist/modules/fanui-overlay.min.css +91 -0
- package/dist/modules/fanui-table.css +290 -0
- package/dist/modules/fanui-table.min.css +62 -0
- package/dist/modules/fanui-tabs.css +333 -0
- package/dist/modules/fanui-tabs.min.css +58 -0
- package/dist/modules/fanui-themes.css +2728 -0
- package/dist/modules/fanui-themes.min.css +40 -0
- package/dist/modules/fanui-tokens.css +587 -0
- package/dist/modules/fanui-tokens.min.css +3 -0
- package/dist/modules/fanui-utilities.css +6557 -0
- package/dist/modules/fanui-utilities.min.css +1762 -0
- package/dist/modules/sizes.json +103 -0
- package/docs/MIGRATION-v2.md +179 -0
- package/examples/01-script-tag.html +149 -0
- package/examples/02-react/README.md +39 -0
- package/examples/02-react/index.html +12 -0
- package/examples/02-react/package.json +20 -0
- package/examples/02-react/src/App.jsx +108 -0
- package/examples/02-react/src/main.jsx +13 -0
- package/examples/02-react/src/useFanUI.js +87 -0
- package/examples/02-react/vite.config.js +6 -0
- package/examples/03-vue3/README.md +67 -0
- package/examples/03-vue3/index.html +12 -0
- package/examples/03-vue3/package.json +19 -0
- package/examples/03-vue3/src/App.vue +93 -0
- package/examples/03-vue3/src/main.js +8 -0
- package/examples/03-vue3/src/useFanUI.js +85 -0
- package/examples/03-vue3/vite.config.js +6 -0
- package/examples/04-vue2-cdn.html +93 -0
- package/examples/README.md +34 -0
- package/package.json +127 -0
- package/src/_functions.scss +319 -0
- package/src/_mixins.scss +1202 -0
- package/src/_tokens.scss +180 -0
- package/src/_variables.scss +491 -0
- package/src/base/_animations.scss +210 -0
- package/src/base/_reset.scss +359 -0
- package/src/base/_rtl.scss +133 -0
- package/src/base/_typography.scss +353 -0
- package/src/components/_advanced.scss +763 -0
- package/src/components/_alert.scss +322 -0
- package/src/components/_badge.scss +279 -0
- package/src/components/_blog.scss +693 -0
- package/src/components/_button.scss +351 -0
- package/src/components/_capabilities.scss +463 -0
- package/src/components/_card.scss +281 -0
- package/src/components/_choice.scss +444 -0
- package/src/components/_dashboard.scss +950 -0
- package/src/components/_data.scss +618 -0
- package/src/components/_feedback.scss +403 -0
- package/src/components/_form.scss +408 -0
- package/src/components/_glass.scss +374 -0
- package/src/components/_input-plus.scss +730 -0
- package/src/components/_interactive.scss +885 -0
- package/src/components/_marketing.scss +982 -0
- package/src/components/_nav.scss +480 -0
- package/src/components/_overlay.scss +517 -0
- package/src/components/_table.scss +276 -0
- package/src/components/_tabs.scss +338 -0
- package/src/fanui.d.ts +353 -0
- package/src/fanui.js +4782 -0
- package/src/fanui.scss +79 -0
- package/src/glass/_switches.scss +36 -0
- package/src/glass/_tokens.scss +259 -0
- package/src/layout/_container.scss +111 -0
- package/src/layout/_flex.scss +164 -0
- package/src/layout/_grid.scss +180 -0
- package/src/themes/_accents.scss +201 -0
- package/src/themes/_palettes.scss +180 -0
- package/src/utilities/_borders.scss +104 -0
- package/src/utilities/_display.scss +145 -0
- package/src/utilities/_effects.scss +210 -0
- package/src/utilities/_sizing.scss +123 -0
- package/src/utilities/_spacing.scss +118 -0
- package/src/utilities/_texture.scss +323 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// fanUI · 显示 / 定位 / 溢出 / 层级 工具类
|
|
3
|
+
// =============================================================================
|
|
4
|
+
|
|
5
|
+
@use "sass:map";
|
|
6
|
+
@use "../functions" as fn;
|
|
7
|
+
@use "../variables" as v;
|
|
8
|
+
@use "../mixins" as mx;
|
|
9
|
+
|
|
10
|
+
// -----------------------------------------------------------------------------
|
|
11
|
+
// 1. 可见性
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
.fanui-visible { visibility: visible; }
|
|
15
|
+
.fanui-invisible { visibility: hidden; }
|
|
16
|
+
.fanui-collapse { visibility: collapse; }
|
|
17
|
+
|
|
18
|
+
.fanui-hidden { display: none !important; }
|
|
19
|
+
.fanui-opacity-0 { opacity: 0; }
|
|
20
|
+
.fanui-opacity-25 { opacity: 0.25; }
|
|
21
|
+
.fanui-opacity-50 { opacity: 0.5; }
|
|
22
|
+
.fanui-opacity-75 { opacity: 0.75; }
|
|
23
|
+
.fanui-opacity-100 { opacity: 1; }
|
|
24
|
+
|
|
25
|
+
// -----------------------------------------------------------------------------
|
|
26
|
+
// 2. 定位
|
|
27
|
+
// -----------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
.fanui-static { position: static; }
|
|
30
|
+
.fanui-relative { position: relative; }
|
|
31
|
+
.fanui-absolute { position: absolute; }
|
|
32
|
+
.fanui-fixed { position: fixed; }
|
|
33
|
+
.fanui-sticky { position: sticky; }
|
|
34
|
+
|
|
35
|
+
// inset
|
|
36
|
+
@each $key, $value in (0: 0, 1: 4px, 2: 8px, 3: 12px, 4: 16px, 6: 24px, 8: 32px) {
|
|
37
|
+
.fanui-top-#{$key} { top: $value; }
|
|
38
|
+
.fanui-right-#{$key} { right: $value; }
|
|
39
|
+
.fanui-bottom-#{$key} { bottom: $value; }
|
|
40
|
+
.fanui-left-#{$key} { left: $value; }
|
|
41
|
+
}
|
|
42
|
+
.fanui-inset-0 { inset: 0; }
|
|
43
|
+
.fanui-top-auto { top: auto; }
|
|
44
|
+
.fanui-right-auto { right: auto; }
|
|
45
|
+
.fanui-bottom-auto { bottom: auto; }
|
|
46
|
+
.fanui-left-auto { left: auto; }
|
|
47
|
+
|
|
48
|
+
.fanui-absolute-center {
|
|
49
|
+
@include mx.fanui-abs-center(both);
|
|
50
|
+
}
|
|
51
|
+
.fanui-absolute-fill {
|
|
52
|
+
@include mx.fanui-absolute-fill();
|
|
53
|
+
}
|
|
54
|
+
.fanui-fixed-fill {
|
|
55
|
+
@include mx.fanui-fixed-fill();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 层级
|
|
59
|
+
@each $name, $value in v.$fanui-zindexes {
|
|
60
|
+
.fanui-z-#{$name} { z-index: $value; }
|
|
61
|
+
}
|
|
62
|
+
@for $i from 0 through 5 {
|
|
63
|
+
.fanui-z-#{$i * 10} { z-index: $i * 10; }
|
|
64
|
+
}
|
|
65
|
+
.fanui-z-auto { z-index: auto; }
|
|
66
|
+
|
|
67
|
+
// -----------------------------------------------------------------------------
|
|
68
|
+
// 3. 溢出 / 滚动
|
|
69
|
+
// -----------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
.fanui-overflow-auto { overflow: auto; }
|
|
72
|
+
.fanui-overflow-hidden { overflow: hidden; }
|
|
73
|
+
.fanui-overflow-visible { overflow: visible; }
|
|
74
|
+
.fanui-overflow-scroll { overflow: scroll; }
|
|
75
|
+
.fanui-overflow-x-auto { overflow-x: auto; }
|
|
76
|
+
.fanui-overflow-y-auto { overflow-y: auto; }
|
|
77
|
+
.fanui-overflow-x-hidden { overflow-x: hidden; }
|
|
78
|
+
.fanui-overflow-y-hidden { overflow-y: hidden; }
|
|
79
|
+
|
|
80
|
+
.fanui-scroll-smooth { scroll-behavior: smooth; }
|
|
81
|
+
.fanui-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
|
82
|
+
.fanui-scroll-y { overflow-y: auto; -webkit-overflow-scrolling: touch; }
|
|
83
|
+
|
|
84
|
+
// -----------------------------------------------------------------------------
|
|
85
|
+
// 4. 浮动 / 清除
|
|
86
|
+
// -----------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
.fanui-float-start { float: left; }
|
|
89
|
+
.fanui-float-end { float: right; }
|
|
90
|
+
.fanui-float-none { float: none; }
|
|
91
|
+
.fanui-clearfix { @include mx.fanui-clearfix(); }
|
|
92
|
+
.fanui-clear-both { clear: both; }
|
|
93
|
+
|
|
94
|
+
// -----------------------------------------------------------------------------
|
|
95
|
+
// 5. 容器查询 / 响应式隐藏
|
|
96
|
+
// -----------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
.fanui-block-sm, .fanui-block-md, .fanui-block-lg, .fanui-block-xl { display: none; }
|
|
99
|
+
|
|
100
|
+
@each $bp, $min in v.$fanui-breakpoints {
|
|
101
|
+
@if $bp != "xs" {
|
|
102
|
+
@include mx.fanui-media($bp, min) {
|
|
103
|
+
.fanui-hide-#{$bp}-up { display: none !important; }
|
|
104
|
+
.fanui-block-#{$bp} { display: block; }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 向下隐藏(小于该断点)
|
|
108
|
+
@include mx.fanui-media($bp, max) {
|
|
109
|
+
.fanui-hide-#{$bp}-down { display: none !important; }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.fanui-print-only { display: none; }
|
|
115
|
+
|
|
116
|
+
@media print {
|
|
117
|
+
.fanui-no-print { display: none !important; }
|
|
118
|
+
.fanui-print-only { display: block !important; }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// -----------------------------------------------------------------------------
|
|
122
|
+
// 6. 交互与光标
|
|
123
|
+
// -----------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
.fanui-pointer { cursor: pointer; }
|
|
126
|
+
.fanui-cursor-default { cursor: default; }
|
|
127
|
+
.fanui-cursor-text { cursor: text; }
|
|
128
|
+
.fanui-cursor-move { cursor: move; }
|
|
129
|
+
.fanui-cursor-grab { cursor: grab; }
|
|
130
|
+
.fanui-cursor-help { cursor: help; }
|
|
131
|
+
.fanui-not-allowed { cursor: not-allowed; }
|
|
132
|
+
|
|
133
|
+
.fanui-select-none { user-select: none; -webkit-user-select: none; }
|
|
134
|
+
.fanui-select-all { user-select: all; }
|
|
135
|
+
.fanui-select-text { user-select: text; }
|
|
136
|
+
|
|
137
|
+
.fanui-no-pointer-events { pointer-events: none; }
|
|
138
|
+
.fanui-pointer-events { pointer-events: auto; }
|
|
139
|
+
|
|
140
|
+
.fanui-resize-none { resize: none; }
|
|
141
|
+
.fanui-resize-y { resize: vertical; }
|
|
142
|
+
.fanui-resize-both { resize: both; }
|
|
143
|
+
|
|
144
|
+
.fanui-touch-none { touch-action: none; }
|
|
145
|
+
.fanui-touch-pan-y { touch-action: pan-y; }
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// fanUI · 视觉效果工具类 (Effects)
|
|
3
|
+
// -----------------------------------------------------------------------------
|
|
4
|
+
// 阴影 / 透明 / 滤镜 / 背景 / 变换 / 毛玻璃
|
|
5
|
+
// =============================================================================
|
|
6
|
+
|
|
7
|
+
@use "sass:map";
|
|
8
|
+
@use "../functions" as fn;
|
|
9
|
+
@use "../variables" as v;
|
|
10
|
+
@use "../mixins" as mx;
|
|
11
|
+
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
// 1. 阴影
|
|
14
|
+
// -----------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
@each $name, $value in v.$fanui-shadows {
|
|
17
|
+
.fanui-shadow-#{$name} { box-shadow: fn.fanui-var("shadow-#{$name}", $value); }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.fanui-shadow-primary { box-shadow: 0 6px 16px -6px fn.fanui-var("primary-glow"); }
|
|
21
|
+
.fanui-shadow-accent { box-shadow: 0 6px 16px -6px fn.fanui-var("accent-glow"); }
|
|
22
|
+
.fanui-shadow-focus { box-shadow: 0 0 0 3px fn.fanui-var("primary-ring"); }
|
|
23
|
+
.fanui-shadow-glow { box-shadow: 0 0 24px -4px fn.fanui-var("primary-glow"); }
|
|
24
|
+
.fanui-shadow-glow-accent { box-shadow: 0 0 28px -6px fn.fanui-var("accent-glow"); }
|
|
25
|
+
// 玻璃厚度阴影工具类:公式内联,元素级 --fanui-glass-intensity 同样生效
|
|
26
|
+
.fanui-shadow-glass { @include mx.fanui-glass-depth(); }
|
|
27
|
+
|
|
28
|
+
.fanui-text-shadow-sm { text-shadow: 0 1px 2px rgba(15, 23, 42, 0.2); }
|
|
29
|
+
.fanui-text-shadow-glass { text-shadow: var(--fanui-glass-text-shadow); }
|
|
30
|
+
|
|
31
|
+
// -----------------------------------------------------------------------------
|
|
32
|
+
// 2. 背景
|
|
33
|
+
// -----------------------------------------------------------------------------
|
|
34
|
+
// 说明:液态玻璃(.fanui-glass 系列)已迁移到 components/_glass.scss,
|
|
35
|
+
// 那里提供可调强度、厚度预设、镜面高光与开关降级。
|
|
36
|
+
|
|
37
|
+
.fanui-bg-transparent { background-color: transparent !important; }
|
|
38
|
+
.fanui-bg-surface { background-color: fn.fanui-var("color-surface"); }
|
|
39
|
+
.fanui-bg-sunken { background-color: fn.fanui-var("color-surface-sunken"); }
|
|
40
|
+
.fanui-bg-body { background-color: fn.fanui-var("color-bg"); }
|
|
41
|
+
.fanui-bg-none { background-image: none; }
|
|
42
|
+
|
|
43
|
+
.fanui-bg-gradient-primary {
|
|
44
|
+
@include mx.fanui-gradient(fn.fanui-var("primary"), fn.fanui-var("accent"), to bottom right);
|
|
45
|
+
color: fn.fanui-var("color-text-inverse");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.fanui-bg-gradient-sunset {
|
|
49
|
+
background-image: linear-gradient(135deg, #f59e0b 0%, #ef4444 55%, #8b5cf6 100%);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.fanui-bg-grid {
|
|
53
|
+
background-image:
|
|
54
|
+
linear-gradient(fn.fanui-alpha(#64748b, 0.12) 1px, transparent 1px),
|
|
55
|
+
linear-gradient(90deg, fn.fanui-alpha(#64748b, 0.12) 1px, transparent 1px);
|
|
56
|
+
background-size: 20px 20px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 语义背景色(柔和版)
|
|
60
|
+
@each $name, $color in v.$fanui-theme-colors {
|
|
61
|
+
.fanui-bg-#{$name} { background-color: fn.fanui-var("#{$name}"); color: fn.fanui-var("#{$name}-fg"); }
|
|
62
|
+
.fanui-bg-#{$name}-soft { background-color: fn.fanui-var("#{$name}-soft"); }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// -----------------------------------------------------------------------------
|
|
66
|
+
// 2.5 调色板工具类(全色阶):.fanui-bg-primary-500 / .fanui-text-danger-600 …
|
|
67
|
+
// -----------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
@each $name, $tones in v.$fanui-palette {
|
|
70
|
+
@each $tone, $value in $tones {
|
|
71
|
+
.fanui-bg-#{$name}-#{$tone} { background-color: fn.fanui-var("#{$name}-#{$tone}", $value); }
|
|
72
|
+
.fanui-text-#{$name}-#{$tone} { color: fn.fanui-var("#{$name}-#{$tone}", $value); }
|
|
73
|
+
.fanui-border-#{$name}-#{$tone} { border-color: fn.fanui-var("#{$name}-#{$tone}", $value); }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// -----------------------------------------------------------------------------
|
|
78
|
+
// 3. 滤镜 / 变换
|
|
79
|
+
// -----------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
.fanui-blur-sm { filter: blur(4px); }
|
|
82
|
+
.fanui-blur { filter: blur(8px); }
|
|
83
|
+
.fanui-blur-lg { filter: blur(16px); }
|
|
84
|
+
.fanui-grayscale { filter: grayscale(100%); }
|
|
85
|
+
.fanui-sepia { filter: sepia(100%); }
|
|
86
|
+
.fanui-invert { filter: invert(100%); }
|
|
87
|
+
|
|
88
|
+
.fanui-backdrop-blur-sm { backdrop-filter: blur(4px); }
|
|
89
|
+
.fanui-backdrop-blur { backdrop-filter: blur(8px); }
|
|
90
|
+
.fanui-backdrop-blur-lg { backdrop-filter: blur(16px); }
|
|
91
|
+
|
|
92
|
+
.fanui-scale-0 { transform: scale(0); }
|
|
93
|
+
.fanui-scale-90 { transform: scale(0.9); }
|
|
94
|
+
.fanui-scale-95 { transform: scale(0.95); }
|
|
95
|
+
.fanui-scale-100 { transform: scale(1); }
|
|
96
|
+
.fanui-scale-105 { transform: scale(1.05); }
|
|
97
|
+
.fanui-scale-110 { transform: scale(1.1); }
|
|
98
|
+
|
|
99
|
+
.fanui-rotate-45 { transform: rotate(45deg); }
|
|
100
|
+
.fanui-rotate-90 { transform: rotate(90deg); }
|
|
101
|
+
.fanui-rotate-180 { transform: rotate(180deg); }
|
|
102
|
+
|
|
103
|
+
.fanui-translate-y-0 { transform: translateY(0); }
|
|
104
|
+
.fanui-translate-y-up { transform: translateY(-2px); }
|
|
105
|
+
|
|
106
|
+
.fanui-transform-none { transform: none; }
|
|
107
|
+
.fanui-transform-origin-center { transform-origin: center; }
|
|
108
|
+
|
|
109
|
+
// hover 抬升
|
|
110
|
+
.fanui-hover-lift {
|
|
111
|
+
@include mx.fanui-transition((transform, box-shadow), v.$fanui-duration-base);
|
|
112
|
+
|
|
113
|
+
&:hover {
|
|
114
|
+
transform: translateY(-2px);
|
|
115
|
+
box-shadow: fn.fanui-var("shadow-lg");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.fanui-hover-scale {
|
|
120
|
+
@include mx.fanui-transition(transform, v.$fanui-duration-fast);
|
|
121
|
+
|
|
122
|
+
&:hover { transform: scale(1.03); }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.fanui-hover-shadow {
|
|
126
|
+
@include mx.fanui-transition(box-shadow, v.$fanui-duration-base);
|
|
127
|
+
|
|
128
|
+
&:hover { box-shadow: fn.fanui-var("shadow-md"); }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// -----------------------------------------------------------------------------
|
|
132
|
+
// 4. 遮罩层(backdrop)
|
|
133
|
+
// -----------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
.fanui-backdrop {
|
|
136
|
+
@include mx.fanui-backdrop();
|
|
137
|
+
opacity: 0;
|
|
138
|
+
visibility: hidden;
|
|
139
|
+
@include mx.fanui-transition((opacity, visibility), v.$fanui-duration-base);
|
|
140
|
+
|
|
141
|
+
&.is-open,
|
|
142
|
+
&.is-active {
|
|
143
|
+
opacity: 1;
|
|
144
|
+
visibility: visible;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// -----------------------------------------------------------------------------
|
|
149
|
+
// 5. 焦点 / 无障碍
|
|
150
|
+
// -----------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
.fanui-focus-ring {
|
|
153
|
+
&:focus-visible { @include mx.fanui-focus-ring(); }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.fanui-focus-within {
|
|
157
|
+
&:focus-within { @include mx.fanui-focus-ring(); }
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.fanui-outline-none { outline: none; }
|
|
161
|
+
|
|
162
|
+
// -----------------------------------------------------------------------------
|
|
163
|
+
// 6. 杂项
|
|
164
|
+
// -----------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
.fanui-object-cover { object-fit: cover; }
|
|
167
|
+
.fanui-object-contain { object-fit: contain; }
|
|
168
|
+
.fanui-object-center { object-position: center; }
|
|
169
|
+
|
|
170
|
+
.fanui-isolate { isolation: isolate; }
|
|
171
|
+
.fanui-mix-blend-multiply { mix-blend-mode: multiply; }
|
|
172
|
+
|
|
173
|
+
.fanui-ring-primary { box-shadow: 0 0 0 3px fn.fanui-var("primary-ring"); }
|
|
174
|
+
|
|
175
|
+
// -----------------------------------------------------------------------------
|
|
176
|
+
// 7. 入场动画(配合 FanUI.scroll.reveal / IntersectionObserver)
|
|
177
|
+
// -----------------------------------------------------------------------------
|
|
178
|
+
// JS 在 <html> 上写入 data-fanui-reveal-ready,并为进入视口的元素加 .is-visible。
|
|
179
|
+
// 若 JS 未运行,data-fanui-reveal-ready 不存在,元素直接可见 —— 天然的渐进增强。
|
|
180
|
+
|
|
181
|
+
[data-fanui-reveal-ready] [data-fanui-reveal] {
|
|
182
|
+
opacity: 0;
|
|
183
|
+
transform: translateY(18px);
|
|
184
|
+
transition:
|
|
185
|
+
opacity v.$fanui-duration-slower v.$fanui-ease-out,
|
|
186
|
+
transform v.$fanui-duration-slower v.$fanui-ease-out;
|
|
187
|
+
transition-delay: var(--fanui-reveal-delay, 0ms);
|
|
188
|
+
will-change: opacity, transform;
|
|
189
|
+
|
|
190
|
+
&.is-visible {
|
|
191
|
+
opacity: 1;
|
|
192
|
+
transform: none;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// 变体:从不同方向淡入
|
|
197
|
+
[data-fanui-reveal-ready] [data-fanui-reveal="left"] { transform: translateX(-24px); }
|
|
198
|
+
[data-fanui-reveal-ready] [data-fanui-reveal="right"] { transform: translateX(24px); }
|
|
199
|
+
[data-fanui-reveal-ready] [data-fanui-reveal="scale"] { transform: scale(0.94); }
|
|
200
|
+
[data-fanui-reveal-ready] [data-fanui-reveal="fade"] { transform: none; }
|
|
201
|
+
|
|
202
|
+
[data-fanui-reveal-ready] [data-fanui-reveal].is-visible { transform: none; }
|
|
203
|
+
|
|
204
|
+
@media (prefers-reduced-motion: reduce) {
|
|
205
|
+
[data-fanui-reveal-ready] [data-fanui-reveal] {
|
|
206
|
+
opacity: 1;
|
|
207
|
+
transform: none;
|
|
208
|
+
transition: none;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// fanUI · 尺寸工具类 (Sizing)
|
|
3
|
+
// =============================================================================
|
|
4
|
+
|
|
5
|
+
@use "sass:math";
|
|
6
|
+
@use "../functions" as fn;
|
|
7
|
+
@use "../variables" as v;
|
|
8
|
+
@use "../mixins" as mx;
|
|
9
|
+
|
|
10
|
+
// -----------------------------------------------------------------------------
|
|
11
|
+
// 1. 百分比宽度
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
$fanui-percentages: (
|
|
15
|
+
0: 0%, 5: 5%, 10: 10%, 15: 15%, 20: 20%, 25: 25%, 30: 30%, 33: 33.3333%,
|
|
16
|
+
35: 35%, 40: 40%, 45: 45%, 50: 50%, 55: 55%, 60: 60%, 65: 65%,
|
|
17
|
+
66: 66.6667%, 70: 70%, 75: 75%, 80: 80%, 85: 85%, 90: 90%, 95: 95%, 100: 100%
|
|
18
|
+
) !default;
|
|
19
|
+
|
|
20
|
+
@each $name, $value in $fanui-percentages {
|
|
21
|
+
.fanui-w-#{$name} { width: $value; }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.fanui-w-auto { width: auto; }
|
|
25
|
+
.fanui-w-full { width: 100%; }
|
|
26
|
+
.fanui-w-screen { width: 100vw; }
|
|
27
|
+
.fanui-w-min { width: min-content; }
|
|
28
|
+
.fanui-w-max { width: max-content; }
|
|
29
|
+
.fanui-w-fit { width: fit-content; }
|
|
30
|
+
.fanui-h-auto { height: auto; }
|
|
31
|
+
.fanui-h-full { height: 100%; }
|
|
32
|
+
.fanui-h-screen { height: 100vh; }
|
|
33
|
+
.fanui-h-dvh { height: 100dvh; }
|
|
34
|
+
.fanui-h-svh { height: 100svh; }
|
|
35
|
+
|
|
36
|
+
.fanui-min-w-0 { min-width: 0; }
|
|
37
|
+
.fanui-min-w-full { min-width: 100%; }
|
|
38
|
+
.fanui-max-w-full { max-width: 100%; }
|
|
39
|
+
.fanui-max-w-none { max-width: none; }
|
|
40
|
+
.fanui-min-h-0 { min-height: 0; }
|
|
41
|
+
.fanui-min-h-full { min-height: 100%; }
|
|
42
|
+
.fanui-max-h-full { max-height: 100%; }
|
|
43
|
+
|
|
44
|
+
// -----------------------------------------------------------------------------
|
|
45
|
+
// 2. 间距标尺尺寸(4px 基准)
|
|
46
|
+
// -----------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
@each $key, $value in v.$fanui-spacers-utilities {
|
|
49
|
+
.fanui-w-#{$key} { width: $value; }
|
|
50
|
+
.fanui-h-#{$key} { height: $value; }
|
|
51
|
+
.fanui-size-#{$key} { width: $value; height: $value; }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// -----------------------------------------------------------------------------
|
|
55
|
+
// 3. 语义化尺寸
|
|
56
|
+
// -----------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
.fanui-w-xs { width: 320px; }
|
|
59
|
+
.fanui-w-sm { width: 480px; }
|
|
60
|
+
.fanui-w-md { width: 640px; }
|
|
61
|
+
.fanui-w-lg { width: 800px; }
|
|
62
|
+
.fanui-w-xl { width: 1024px; }
|
|
63
|
+
.fanui-w-2xl { width: 1280px; }
|
|
64
|
+
|
|
65
|
+
.fanui-max-w-xs { max-width: 320px; }
|
|
66
|
+
.fanui-max-w-sm { max-width: 480px; }
|
|
67
|
+
.fanui-max-w-md { max-width: 640px; }
|
|
68
|
+
.fanui-max-w-lg { max-width: 800px; }
|
|
69
|
+
.fanui-max-w-xl { max-width: 1024px; }
|
|
70
|
+
.fanui-max-w-2xl { max-width: 1280px; }
|
|
71
|
+
.fanui-max-w-prose { max-width: 72ch; }
|
|
72
|
+
|
|
73
|
+
// -----------------------------------------------------------------------------
|
|
74
|
+
// 4. 宽高比
|
|
75
|
+
// -----------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
.fanui-ratio-square { aspect-ratio: 1 / 1; }
|
|
78
|
+
.fanui-ratio-video { aspect-ratio: 16 / 9; }
|
|
79
|
+
.fanui-ratio-4-3 { aspect-ratio: 4 / 3; }
|
|
80
|
+
.fanui-ratio-3-2 { aspect-ratio: 3 / 2; }
|
|
81
|
+
.fanui-ratio-21-9 { aspect-ratio: 21 / 9; }
|
|
82
|
+
|
|
83
|
+
// 媒体比例容器(兼容不支持 aspect-ratio 的场景)
|
|
84
|
+
.fanui-ratio {
|
|
85
|
+
position: relative;
|
|
86
|
+
width: 100%;
|
|
87
|
+
|
|
88
|
+
&::before {
|
|
89
|
+
content: "";
|
|
90
|
+
display: block;
|
|
91
|
+
padding-top: calc(100% * var(--fanui-ratio-h, 9) / var(--fanui-ratio-w, 16));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
> * {
|
|
95
|
+
@include mx.fanui-absolute-fill();
|
|
96
|
+
width: 100%;
|
|
97
|
+
height: 100%;
|
|
98
|
+
object-fit: cover;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&--square { --fanui-ratio-w: 1; --fanui-ratio-h: 1; }
|
|
102
|
+
&--4-3 { --fanui-ratio-w: 4; --fanui-ratio-h: 3; }
|
|
103
|
+
&--16-9 { --fanui-ratio-w: 16; --fanui-ratio-h: 9; }
|
|
104
|
+
&--21-9 { --fanui-ratio-w: 21; --fanui-ratio-h: 9; }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// -----------------------------------------------------------------------------
|
|
108
|
+
// 5. 响应式宽度
|
|
109
|
+
// -----------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
@each $bp, $min in v.$fanui-breakpoints {
|
|
112
|
+
@if $bp != "xs" {
|
|
113
|
+
@include mx.fanui-media($bp, min) {
|
|
114
|
+
.fanui-w-#{$bp}-full { width: 100%; }
|
|
115
|
+
.fanui-w-#{$bp}-auto { width: auto; }
|
|
116
|
+
@each $name, $value in $fanui-percentages {
|
|
117
|
+
@if $name % 25 == 0 {
|
|
118
|
+
.fanui-w-#{$bp}-#{$name} { width: $value; }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// fanUI · 间距工具类 (Spacing)
|
|
3
|
+
// -----------------------------------------------------------------------------
|
|
4
|
+
// 命名:.fanui-{m|p}{t|r|b|l|x|y|""}-<key>[-<bp>]
|
|
5
|
+
// m = margin, p = padding
|
|
6
|
+
// 方向:t=上 r=右 b=下 l=左 x=左右 y=上下(缺省=四向)
|
|
7
|
+
// key 取自 4px 基准间距标尺:0 1 2 3 4 5 6 8 10 12 16 20 24 与 auto
|
|
8
|
+
// 示例:.fanui-mt-4 .fanui-px-6 .fanui-m-md-8 .fanui-mx-auto
|
|
9
|
+
// =============================================================================
|
|
10
|
+
|
|
11
|
+
@use "sass:map";
|
|
12
|
+
@use "../functions" as fn;
|
|
13
|
+
@use "../variables" as v;
|
|
14
|
+
@use "../mixins" as mx;
|
|
15
|
+
|
|
16
|
+
// 方向 -> 属性映射
|
|
17
|
+
// ★ 行内轴一律用 **逻辑属性**(inline-start / inline-end),而不是 left / right。
|
|
18
|
+
// 这样 .fanui-ml-4 在 LTR 下等价于 margin-inline-start:4,在 [dir="rtl"] 下自动变成右侧,
|
|
19
|
+
// 无需任何镜像覆盖层 —— 这也是本项目 RTL 覆盖率从个位数提升到全量的关键。
|
|
20
|
+
// 显式要「物理左/右」时请用 .fanui-text-left / .fanui-text-right。
|
|
21
|
+
$fanui-space-sides: (
|
|
22
|
+
"": (margin,),
|
|
23
|
+
"t": (margin-top,),
|
|
24
|
+
"r": (margin-inline-end,),
|
|
25
|
+
"b": (margin-bottom,),
|
|
26
|
+
"l": (margin-inline-start,),
|
|
27
|
+
"x": (margin-inline,),
|
|
28
|
+
"y": (margin-top, margin-bottom),
|
|
29
|
+
) !default;
|
|
30
|
+
|
|
31
|
+
$fanui-pad-sides: (
|
|
32
|
+
"": (padding,),
|
|
33
|
+
"t": (padding-top,),
|
|
34
|
+
"r": (padding-inline-end,),
|
|
35
|
+
"b": (padding-bottom,),
|
|
36
|
+
"l": (padding-inline-start,),
|
|
37
|
+
"x": (padding-inline,),
|
|
38
|
+
"y": (padding-top, padding-bottom),
|
|
39
|
+
) !default;
|
|
40
|
+
|
|
41
|
+
// -----------------------------------------------------------------------------
|
|
42
|
+
// 1. 无断点:margin / padding
|
|
43
|
+
// -----------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
@each $key, $value in v.$fanui-spacers-utilities {
|
|
46
|
+
@each $side, $props in $fanui-space-sides {
|
|
47
|
+
.fanui-m#{$side}-#{$key} {
|
|
48
|
+
@each $prop in $props { #{$prop}: $value; }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@each $side, $props in $fanui-pad-sides {
|
|
53
|
+
.fanui-p#{$side}-#{$key} {
|
|
54
|
+
@each $prop in $props { #{$prop}: $value; }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// -----------------------------------------------------------------------------
|
|
60
|
+
// 2. auto 间距(居中对齐等)
|
|
61
|
+
// -----------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
.fanui-mx-auto { margin-inline-start: auto; margin-inline-end: auto; }
|
|
64
|
+
.fanui-my-auto { margin-top: auto; margin-bottom: auto; }
|
|
65
|
+
.fanui-mt-auto { margin-top: auto; }
|
|
66
|
+
.fanui-mb-auto { margin-bottom: auto; }
|
|
67
|
+
.fanui-ml-auto { margin-inline-start: auto; }
|
|
68
|
+
.fanui-mr-auto { margin-inline-end: auto; }
|
|
69
|
+
.fanui-m-auto { margin: auto; }
|
|
70
|
+
|
|
71
|
+
// -----------------------------------------------------------------------------
|
|
72
|
+
// 3. 响应式间距:.fanui-m<side>-<bp>-<key>
|
|
73
|
+
// -----------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
@each $bp, $min in v.$fanui-breakpoints {
|
|
76
|
+
@if $bp != "xs" {
|
|
77
|
+
@include mx.fanui-media($bp, min) {
|
|
78
|
+
@each $key, $value in v.$fanui-spacers-utilities {
|
|
79
|
+
@each $side, $props in $fanui-space-sides {
|
|
80
|
+
.fanui-m#{$side}-#{$bp}-#{$key} {
|
|
81
|
+
@each $prop in $props { #{$prop}: $value; }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@each $side, $props in $fanui-pad-sides {
|
|
86
|
+
.fanui-p#{$side}-#{$bp}-#{$key} {
|
|
87
|
+
@each $prop in $props { #{$prop}: $value; }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.fanui-mx-#{$bp}-auto { margin-inline: auto; }
|
|
93
|
+
.fanui-mt-#{$bp}-auto { margin-top: auto; }
|
|
94
|
+
.fanui-mb-#{$bp}-auto { margin-bottom: auto; }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// -----------------------------------------------------------------------------
|
|
100
|
+
// 4. 语义化间距快捷类
|
|
101
|
+
// -----------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
.fanui-p-section { padding: fn.fanui-var("space-8"); }
|
|
104
|
+
.fanui-p-card { padding: fn.fanui-var("space-5"); }
|
|
105
|
+
.fanui-gap-card { gap: fn.fanui-var("space-4"); }
|
|
106
|
+
|
|
107
|
+
// 相邻元素自动间距(替代手写 margin)
|
|
108
|
+
.fanui-stack-space > * + * { margin-top: fn.fanui-var("space-4"); }
|
|
109
|
+
.fanui-stack-space-sm > * + * { margin-top: fn.fanui-var("space-2"); }
|
|
110
|
+
.fanui-stack-space-lg > * + * { margin-top: fn.fanui-var("space-6"); }
|
|
111
|
+
|
|
112
|
+
.fanui-inline-space > * + * { margin-inline-start: fn.fanui-var("space-3"); }
|
|
113
|
+
|
|
114
|
+
// 首尾元素去边距
|
|
115
|
+
.fanui-trim > :first-child { margin-top: 0; }
|
|
116
|
+
.fanui-trim > :last-child { margin-bottom: 0; }
|
|
117
|
+
.fanui-trim-v > :first-child { margin-top: 0; }
|
|
118
|
+
.fanui-trim-v > :last-child { margin-bottom: 0; }
|