@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.
Files changed (127) hide show
  1. package/ACCESSIBILITY.md +61 -0
  2. package/CHANGELOG.md +112 -0
  3. package/COMMERCIAL-LICENSE.md +71 -0
  4. package/DESIGN-SYSTEM.md +294 -0
  5. package/LICENSE +661 -0
  6. package/README.md +348 -0
  7. package/USAGE.md +1926 -0
  8. package/_index.scss +20 -0
  9. package/dist/fanui.cjs +15 -0
  10. package/dist/fanui.css +28209 -0
  11. package/dist/fanui.d.ts +353 -0
  12. package/dist/fanui.esm.js +71 -0
  13. package/dist/fanui.js +4782 -0
  14. package/dist/fanui.min.css +1 -0
  15. package/dist/fanui.mjs +71 -0
  16. package/dist/modules/fanui-advanced.css +830 -0
  17. package/dist/modules/fanui-advanced.min.css +129 -0
  18. package/dist/modules/fanui-alert.css +575 -0
  19. package/dist/modules/fanui-alert.min.css +122 -0
  20. package/dist/modules/fanui-badge.css +426 -0
  21. package/dist/modules/fanui-badge.min.css +77 -0
  22. package/dist/modules/fanui-base.css +1394 -0
  23. package/dist/modules/fanui-base.min.css +236 -0
  24. package/dist/modules/fanui-blog.css +762 -0
  25. package/dist/modules/fanui-blog.min.css +108 -0
  26. package/dist/modules/fanui-button.css +526 -0
  27. package/dist/modules/fanui-button.min.css +56 -0
  28. package/dist/modules/fanui-card.css +291 -0
  29. package/dist/modules/fanui-card.min.css +52 -0
  30. package/dist/modules/fanui-choice.css +539 -0
  31. package/dist/modules/fanui-choice.min.css +83 -0
  32. package/dist/modules/fanui-dashboard.css +1057 -0
  33. package/dist/modules/fanui-dashboard.min.css +160 -0
  34. package/dist/modules/fanui-data.css +687 -0
  35. package/dist/modules/fanui-data.min.css +125 -0
  36. package/dist/modules/fanui-feedback.css +432 -0
  37. package/dist/modules/fanui-feedback.min.css +79 -0
  38. package/dist/modules/fanui-form.css +779 -0
  39. package/dist/modules/fanui-form.min.css +123 -0
  40. package/dist/modules/fanui-glass.css +497 -0
  41. package/dist/modules/fanui-glass.min.css +46 -0
  42. package/dist/modules/fanui-input-plus.css +799 -0
  43. package/dist/modules/fanui-input-plus.min.css +124 -0
  44. package/dist/modules/fanui-interactive.css +960 -0
  45. package/dist/modules/fanui-interactive.min.css +138 -0
  46. package/dist/modules/fanui-layout.css +4399 -0
  47. package/dist/modules/fanui-layout.min.css +1172 -0
  48. package/dist/modules/fanui-marketing.css +1125 -0
  49. package/dist/modules/fanui-marketing.min.css +144 -0
  50. package/dist/modules/fanui-nav.css +458 -0
  51. package/dist/modules/fanui-nav.min.css +76 -0
  52. package/dist/modules/fanui-overlay.css +547 -0
  53. package/dist/modules/fanui-overlay.min.css +91 -0
  54. package/dist/modules/fanui-table.css +290 -0
  55. package/dist/modules/fanui-table.min.css +62 -0
  56. package/dist/modules/fanui-tabs.css +333 -0
  57. package/dist/modules/fanui-tabs.min.css +58 -0
  58. package/dist/modules/fanui-themes.css +2728 -0
  59. package/dist/modules/fanui-themes.min.css +40 -0
  60. package/dist/modules/fanui-tokens.css +587 -0
  61. package/dist/modules/fanui-tokens.min.css +3 -0
  62. package/dist/modules/fanui-utilities.css +6557 -0
  63. package/dist/modules/fanui-utilities.min.css +1762 -0
  64. package/dist/modules/sizes.json +103 -0
  65. package/docs/MIGRATION-v2.md +179 -0
  66. package/examples/01-script-tag.html +149 -0
  67. package/examples/02-react/README.md +39 -0
  68. package/examples/02-react/index.html +12 -0
  69. package/examples/02-react/package.json +20 -0
  70. package/examples/02-react/src/App.jsx +108 -0
  71. package/examples/02-react/src/main.jsx +13 -0
  72. package/examples/02-react/src/useFanUI.js +87 -0
  73. package/examples/02-react/vite.config.js +6 -0
  74. package/examples/03-vue3/README.md +67 -0
  75. package/examples/03-vue3/index.html +12 -0
  76. package/examples/03-vue3/package.json +19 -0
  77. package/examples/03-vue3/src/App.vue +93 -0
  78. package/examples/03-vue3/src/main.js +8 -0
  79. package/examples/03-vue3/src/useFanUI.js +85 -0
  80. package/examples/03-vue3/vite.config.js +6 -0
  81. package/examples/04-vue2-cdn.html +93 -0
  82. package/examples/README.md +34 -0
  83. package/package.json +127 -0
  84. package/src/_functions.scss +319 -0
  85. package/src/_mixins.scss +1202 -0
  86. package/src/_tokens.scss +180 -0
  87. package/src/_variables.scss +491 -0
  88. package/src/base/_animations.scss +210 -0
  89. package/src/base/_reset.scss +359 -0
  90. package/src/base/_rtl.scss +133 -0
  91. package/src/base/_typography.scss +353 -0
  92. package/src/components/_advanced.scss +763 -0
  93. package/src/components/_alert.scss +322 -0
  94. package/src/components/_badge.scss +279 -0
  95. package/src/components/_blog.scss +693 -0
  96. package/src/components/_button.scss +351 -0
  97. package/src/components/_capabilities.scss +463 -0
  98. package/src/components/_card.scss +281 -0
  99. package/src/components/_choice.scss +444 -0
  100. package/src/components/_dashboard.scss +950 -0
  101. package/src/components/_data.scss +618 -0
  102. package/src/components/_feedback.scss +403 -0
  103. package/src/components/_form.scss +408 -0
  104. package/src/components/_glass.scss +374 -0
  105. package/src/components/_input-plus.scss +730 -0
  106. package/src/components/_interactive.scss +885 -0
  107. package/src/components/_marketing.scss +982 -0
  108. package/src/components/_nav.scss +480 -0
  109. package/src/components/_overlay.scss +517 -0
  110. package/src/components/_table.scss +276 -0
  111. package/src/components/_tabs.scss +338 -0
  112. package/src/fanui.d.ts +353 -0
  113. package/src/fanui.js +4782 -0
  114. package/src/fanui.scss +79 -0
  115. package/src/glass/_switches.scss +36 -0
  116. package/src/glass/_tokens.scss +259 -0
  117. package/src/layout/_container.scss +111 -0
  118. package/src/layout/_flex.scss +164 -0
  119. package/src/layout/_grid.scss +180 -0
  120. package/src/themes/_accents.scss +201 -0
  121. package/src/themes/_palettes.scss +180 -0
  122. package/src/utilities/_borders.scss +104 -0
  123. package/src/utilities/_display.scss +145 -0
  124. package/src/utilities/_effects.scss +210 -0
  125. package/src/utilities/_sizing.scss +123 -0
  126. package/src/utilities/_spacing.scss +118 -0
  127. package/src/utilities/_texture.scss +323 -0
package/src/fanui.scss ADDED
@@ -0,0 +1,79 @@
1
+ // =============================================================================
2
+ // fanUI · 轻量、可复用、易扩展的 UI 框架基础样式库
3
+ // ---------------------------------------------------------------------------
4
+ // 统一前缀:所有 CSS 类名、SCSS 变量、函数与 mixin 均以 `fanui` 开头
5
+ // · CSS 类 .fanui-btn / .fanui-card / .fanui-col-md-6
6
+ // · 变量 $fanui-primary / $fanui-radius-base
7
+ // · 函数 fanui-px2rem() / fanui-alpha() / fanui-map-deep()
8
+ // · Mixin @include fanui-flex() / fanui-media() / fanui-truncate()
9
+ // · 自定义属性 --fanui-color-text / --fanui-space-4
10
+ //
11
+ // 引入方式(推荐):
12
+ // @use "@zhang_jifan/fanui" with ($fanui-primary: #7c3aed, $fanui-radius-base: 8px);
13
+ //
14
+ // 仅按需引入模块:
15
+ // @use "@zhang_jifan/fanui/src/functions" as fn;
16
+ // @use "@zhang_jifan/fanui/src/mixins" as mx;
17
+ //
18
+ // 版本:2.1.0
19
+ // =============================================================================
20
+
21
+ // ---- 0. 变量配置入口(必须最先)---------------------------------------------
22
+ // @forward 让调用方的 `@use "@zhang_jifan/fanui" with ($fanui-*: ...)` 能穿透配置到 variables
23
+ // 模块(此前只 @use 不 forward,with() 会报 "not declared with !default")。
24
+ // 注意:@forward 必须出现在任何会传递加载 variables 的 @use 之前。
25
+ @forward "variables";
26
+
27
+ // ---- 0. 设计令牌(CSS 自定义属性,必须最先输出)-----------------------------
28
+ @use "tokens";
29
+
30
+ // ---- 0.1 主题色系统(12 套主题色 × 深浅模式 × 局部作用域)------------------
31
+ @use "themes/accents";
32
+
33
+ // ---- 1. 基础层 --------------------------------------------------------------
34
+ @use "base/reset";
35
+ @use "base/typography";
36
+ @use "base/animations";
37
+ // RTL 双向布局覆盖层(仅 [dir="rtl"] 时生效,不影响 LTR 默认输出)
38
+ @use "base/rtl";
39
+
40
+ // ---- 2. 布局层 --------------------------------------------------------------
41
+ @use "layout/container";
42
+ @use "layout/grid";
43
+ @use "layout/flex";
44
+
45
+ // ---- 3. 组件层 --------------------------------------------------------------
46
+ @use "components/button";
47
+ @use "components/input-plus";
48
+ @use "components/interactive";
49
+ @use "components/marketing";
50
+ @use "components/blog";
51
+ @use "components/dashboard";
52
+ @use "components/form";
53
+ @use "components/choice";
54
+ @use "components/card";
55
+ @use "components/table";
56
+ @use "components/badge";
57
+ @use "components/alert";
58
+ @use "components/nav";
59
+ @use "components/tabs";
60
+ @use "components/overlay";
61
+ @use "components/feedback";
62
+ @use "components/data";
63
+ @use "components/advanced";
64
+ // 能力补齐:虚拟滚动 / 灯箱 / 水印 / 引导 / 分割面板 / 吸顶 / 回到顶部
65
+ @use "components/capabilities";
66
+ // 玻璃材质必须最后引入:它以同权重选择器覆盖各组件的默认表面(导航栏 / 弹层 / 卡片…)
67
+ @use "components/glass";
68
+
69
+ // ---- 4. 工具层(放最后,保证优先级)-----------------------------------------
70
+ @use "utilities/spacing";
71
+ @use "utilities/display";
72
+ @use "utilities/sizing";
73
+ @use "utilities/borders";
74
+ @use "utilities/effects";
75
+ @use "utilities/texture";
76
+
77
+ // ---- 5. 运行时开关(必须绝对最后:关闭态与主题块权重相同,靠输出顺序取胜)----
78
+ // data-fanui-glass="off" / prefers-reduced-transparency → 玻璃退化为实体表面
79
+ @use "glass/switches";
@@ -0,0 +1,36 @@
1
+ // =============================================================================
2
+ // fanUI · 液态玻璃运行时开关(Runtime Switches)
3
+ // -----------------------------------------------------------------------------
4
+ // ★ 为什么必须单独成文件、并且最后 @use
5
+ //
6
+ // CSS 自定义属性的覆盖规则是「同权重 → 后声明者胜」。
7
+ // 关闭玻璃的规则(--fanui-glass-intensity:0 / tint-base:1 / tint-k:0 …)
8
+ // 与主题块(:root / [data-fanui-theme="dark"] / :root[data-fanui-theme="light"])
9
+ // 权重相同(均为 0,2,0)。
10
+ //
11
+ // 如果关闭规则跟在令牌层里先输出,就会被后面重新声明玻璃令牌的主题块覆盖 ——
12
+ // 于是出现「明明 data-fanui-glass="off",玻璃底还是半透明」的经典 bug。
13
+ //
14
+ // 因此把开关单独放一层,并作为整个样式表的最后一段输出(见 fanui.scss 末尾),
15
+ // 保证它永远赢下权重相同的比较。
16
+ //
17
+ // 本层内容
18
+ // · data-fanui-glass="off" 全局关闭 → 全部玻璃参数退化为实体表面
19
+ // · prefers-reduced-transparency 系统「减少透明」→ 同上(无障碍)
20
+ // =============================================================================
21
+
22
+ @use "tokens" as gt;
23
+
24
+ /// 全局关闭:<html data-fanui-glass="off"> 或任意容器 [data-fanui-glass="off"]
25
+ :root[data-fanui-glass="off"],
26
+ [data-fanui-glass="off"] {
27
+ @include gt.fanui-emit-glass-off();
28
+ }
29
+
30
+ /// 用户偏好「减少透明」时自动退回实体表面(无障碍:保证文字对比度)
31
+ @media (prefers-reduced-transparency: reduce) {
32
+ :root:not([data-fanui-glass="on"]),
33
+ [data-fanui-glass="auto"] {
34
+ @include gt.fanui-emit-glass-off();
35
+ }
36
+ }
@@ -0,0 +1,259 @@
1
+ // =============================================================================
2
+ // fanUI · 液态玻璃令牌层 (Liquid Glass Tokens)
3
+ // -----------------------------------------------------------------------------
4
+ // 设计目标:把「玻璃」变成一个可调、可关、可降级的参数化材质,而不是一套写死的值。
5
+ //
6
+ // 三层调节机制
7
+ // 1. 强度总旋钮 --fanui-glass-intensity 0 ~ 2,一处调整所有玻璃参数
8
+ // 2. 厚度预设 .fanui-glass--thin|regular|thick|ultra|lens
9
+ // 3. 单点覆盖 任意元素上重写 --fanui-glass-* 即可局部定制
10
+ //
11
+ // ★ 关键实现约束(v2.0.1 修正)
12
+ // CSS 自定义属性在被继承时就已经在「声明它的元素」上完成了 var() 替换。
13
+ // 因此 `--fanui-glass-bg: rgba(var(--tint-rgb), calc(base + k * var(--intensity)))`
14
+ // 只在 :root 上计算一次,元素上再改 --intensity 也不会重算 —— 预设与局部覆盖会失效。
15
+ // 所以本层只输出「基础参数」,而把所有强度公式内联进消费端声明
16
+ // (见 _mixins.scss 的 fanui-glass-tint / -layer / -refraction / -depth / -edge)。
17
+ //
18
+ // 全局开关(由 JS / HTML 控制)
19
+ // <html data-fanui-glass="off"> 关闭液态玻璃 → 每项参数退化为实体表面
20
+ // <html data-fanui-glass="on"> 开启(默认)
21
+ // prefers-reduced-transparency: reduce → 同样退化为实体表面(无障碍)
22
+ // prefers-reduced-motion: reduce → 关闭流动/高光动效
23
+ //
24
+ // 不支持 backdrop-filter 的浏览器 → @supports 降级为实体表面,内容永远可读
25
+ // =============================================================================
26
+
27
+ @use "sass:map";
28
+ @use "sass:list";
29
+ @use "../functions" as fn;
30
+ @use "../variables" as v;
31
+
32
+ /// 液态玻璃厚度预设
33
+ /// @prop intensity 强度系数(同时驱动模糊、底色深度、描边、高光、阴影)
34
+ /// @prop blur 基础模糊半径(px),实际模糊 = blur × intensity
35
+ /// @prop edge 边缘流光宽度
36
+ /// @prop specular 镜面高光强度系数
37
+ ///
38
+ /// 说明:预设刻意不写死 tint-base / tint-k —— 玻璃底色必须跟随深浅模式
39
+ /// (alpha = 当前的 tint-base + tint-k × intensity),
40
+ /// 否则同一预设会在暗色模式下把玻璃「调得过透」。
41
+ $fanui-glass-presets: (
42
+ "thin": (
43
+ "label": "薄 Thin",
44
+ "intensity": 0.5,
45
+ "blur": 10px,
46
+ "edge": 1px,
47
+ "specular": 0.3
48
+ ),
49
+ "regular": (
50
+ "label": "标准 Regular",
51
+ "intensity": 1,
52
+ "blur": 22px,
53
+ "edge": 1px,
54
+ "specular": 0.55
55
+ ),
56
+ "thick": (
57
+ "label": "厚 Thick",
58
+ "intensity": 1.45,
59
+ "blur": 30px,
60
+ "edge": 1.5px,
61
+ "specular": 0.7
62
+ ),
63
+ "ultra": (
64
+ "label": "超厚 Ultra",
65
+ "intensity": 1.9,
66
+ "blur": 44px,
67
+ "edge": 2px,
68
+ "specular": 0.85
69
+ ),
70
+ "lens": (
71
+ "label": "液态透镜 Lens",
72
+ "intensity": 2,
73
+ "blur": 36px,
74
+ "edge": 2px,
75
+ "specular": 1
76
+ )
77
+ ) !default;
78
+
79
+ /// 输出液态玻璃基础参数令牌。浅色 / 深色模式分别调用。
80
+ ///
81
+ /// 只输出「基础参数」+「根级快照(向后兼容)」两类:
82
+ /// · 基础参数:被消费端公式引用,元素级覆盖有效
83
+ /// · 根级快照:--fanui-glass-bg / -filter / -layer / -border / -shadow / -specular /
84
+ /// -specular-size / -divider / -sheen / -edge-hi / -edge-lo / -edge-width
85
+ /// 仅供外部调用方直接引用;它们在 :root 上按当时的 intensity 计算,不随元素级覆盖变化。
86
+ ///
87
+ /// @param $mode light | dark
88
+ @mixin fanui-emit-glass-tokens($mode: light) {
89
+ // ---- 模式相关的基准参数 --------------------------------------------------
90
+ $blur-base: 22px;
91
+ // 模式修正系数:同一预设在不同明暗下的「厚度感」不同。
92
+ // 暗色玻璃需要更强折射才能在深底上显出层次,故放大 blur(22 × 1.09 ≈ 24)。
93
+ $blur-mode-k: 1;
94
+ $tint-base: 0.30;
95
+ $tint-k: 0.24;
96
+ $tint-rgb: "255, 255, 255";
97
+ $sat-k: 70%;
98
+ $bri-k: 8%;
99
+ $sheen-a: 0.16;
100
+ $border-a: 0.40;
101
+ $border-k: 0.30;
102
+ $edge-hi-a: 0.55;
103
+ $edge-lo-a: 0.06;
104
+ $specular: 0.55;
105
+ $shadow-rgb: "2, 6, 23";
106
+ $shadow-a: 0.14;
107
+ $inner-hi: 0.42;
108
+ $text-shadow: 0 1px 1px rgba(15, 23, 42, 0.05);
109
+ $divider-rgb: "15, 23, 42";
110
+ $divider-a: 0.08;
111
+ $surface-rgb: "255, 255, 255";
112
+ $border-solid-rgb: "226, 232, 240";
113
+
114
+ @if $mode == dark {
115
+ // 暗色模式取向:玻璃必须「更实」才能托住浅色文字 ——
116
+ // · tint 更高:intensity=1 时玻璃底约 0.74 不透明度,muted 文字也有稳定衬底
117
+ // · brightness 提升更克制:避免背后亮色内容把玻璃「洗白」
118
+ // · 描边 / 边缘更亮一线:在深底上维持玻璃的轮廓感
119
+ $blur-base: 24px;
120
+ $blur-mode-k: 1.09;
121
+ $tint-base: 0.46;
122
+ $tint-k: 0.28;
123
+ $tint-rgb: "12, 19, 33";
124
+ $sat-k: 56%;
125
+ $bri-k: 10%;
126
+ $sheen-a: 0.09;
127
+ $border-a: 0.16;
128
+ $border-k: 0.16;
129
+ $edge-hi-a: 0.26;
130
+ $edge-lo-a: 0.05;
131
+ $specular: 0.15;
132
+ $shadow-a: 0.45;
133
+ $inner-hi: 0.14;
134
+ $text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
135
+ $divider-rgb: "255, 255, 255";
136
+ $divider-a: 0.10;
137
+ $surface-rgb: "15, 23, 42";
138
+ $border-solid-rgb: "43, 54, 72";
139
+ }
140
+
141
+ // ---- ① 基础参数(消费端公式引用这些)------------------------------------
142
+ --fanui-glass-intensity: 1;
143
+
144
+ --fanui-glass-blur-base: #{$blur-base};
145
+ --fanui-glass-blur-mode-k: #{$blur-mode-k};
146
+ --fanui-glass-tint-base: #{$tint-base};
147
+ --fanui-glass-tint-k: #{$tint-k};
148
+ --fanui-glass-tint-rgb: #{$tint-rgb};
149
+ --fanui-glass-sat-k: #{$sat-k};
150
+ --fanui-glass-bri-k: #{$bri-k};
151
+ --fanui-glass-sheen-a: #{$sheen-a};
152
+ --fanui-glass-border-rgb: 255, 255, 255;
153
+ --fanui-glass-border-a: #{$border-a};
154
+ --fanui-glass-border-k: #{$border-k};
155
+ --fanui-glass-edge-hi-a: #{$edge-hi-a};
156
+ --fanui-glass-edge-lo-a: #{$edge-lo-a};
157
+ --fanui-glass-edge-angle: 150deg;
158
+ --fanui-glass-edge-alpha: 1;
159
+ --fanui-glass-specular-rgb: 255, 255, 255;
160
+ --fanui-glass-specular-a: #{$specular};
161
+ --fanui-glass-specular-alpha: 1;
162
+ --fanui-glass-specular-size-base: 140px;
163
+ --fanui-glass-specular-size-k: 160px;
164
+ --fanui-glass-shadow-rgb: #{$shadow-rgb};
165
+ --fanui-glass-shadow-a: #{$shadow-a};
166
+ --fanui-glass-shadow-k: 0.10;
167
+ --fanui-glass-shadow-y-k: 8px;
168
+ --fanui-glass-shadow-blur-k: 30px;
169
+ --fanui-glass-shadow-spread-k: -12px;
170
+ --fanui-glass-inner-hi: #{$inner-hi};
171
+ --fanui-glass-divider-rgb: #{$divider-rgb};
172
+ --fanui-glass-divider-a: #{$divider-a};
173
+ --fanui-glass-text-shadow: #{$text-shadow};
174
+ --fanui-glass-mx: 30%;
175
+ --fanui-glass-my: 0%;
176
+
177
+ // 关闭玻璃时用来「退回实体表面」的颜色通道
178
+ --fanui-glass-surface-rgb: #{$surface-rgb};
179
+ --fanui-glass-border-solid-rgb: #{$border-solid-rgb};
180
+ --fanui-glass-fallback-bg: var(--fanui-color-surface);
181
+
182
+ // ---- ② 根级快照(向后兼容;不随元素级 intensity 覆盖变化)---------------
183
+ --fanui-glass-filter: blur(calc(#{$blur-base} * var(--fanui-glass-intensity) * #{$blur-mode-k}))
184
+ saturate(calc(100% + #{$sat-k} * var(--fanui-glass-intensity)))
185
+ brightness(calc(100% + #{$bri-k} * var(--fanui-glass-intensity)));
186
+ --fanui-glass-bg: rgba(
187
+ #{$tint-rgb},
188
+ calc(#{$tint-base} + #{$tint-k} * var(--fanui-glass-intensity))
189
+ );
190
+ --fanui-glass-sheen: linear-gradient(
191
+ 180deg,
192
+ rgba(255, 255, 255, calc(#{$sheen-a} * var(--fanui-glass-intensity))) 0%,
193
+ rgba(255, 255, 255, 0) 46%
194
+ );
195
+ --fanui-glass-border-width: 1px;
196
+ --fanui-glass-border: rgba(255, 255, 255, calc(#{$border-a} + #{$border-k} * var(--fanui-glass-intensity)));
197
+ --fanui-glass-edge-width: calc(1px + 0.5px * var(--fanui-glass-intensity));
198
+ --fanui-glass-edge-hi: rgba(255, 255, 255, calc(#{$edge-hi-a} * min(1, var(--fanui-glass-intensity))));
199
+ --fanui-glass-edge-lo: rgba(255, 255, 255, calc(#{$edge-lo-a} * var(--fanui-glass-intensity)));
200
+ --fanui-glass-specular: rgba(
201
+ 255,
202
+ 255,
203
+ 255,
204
+ calc(#{$specular} * var(--fanui-glass-intensity) * var(--fanui-glass-specular-alpha))
205
+ );
206
+ --fanui-glass-specular-size: calc(140px + 160px * var(--fanui-glass-intensity));
207
+ --fanui-glass-layer: radial-gradient(
208
+ var(--fanui-glass-specular-size) circle at var(--fanui-glass-mx, 30%) var(--fanui-glass-my, 0%),
209
+ var(--fanui-glass-specular),
210
+ transparent 70%
211
+ ),
212
+ var(--fanui-glass-sheen);
213
+ --fanui-glass-shadow:
214
+ 0 calc(8px * var(--fanui-glass-intensity)) calc(30px * var(--fanui-glass-intensity))
215
+ calc(-12px * var(--fanui-glass-intensity))
216
+ rgba(#{$shadow-rgb}, calc(#{$shadow-a} + 0.10 * var(--fanui-glass-intensity))),
217
+ inset 0 1px 0 rgba(255, 255, 255, calc(#{$inner-hi} * min(1, var(--fanui-glass-intensity))));
218
+ --fanui-glass-divider: rgba(#{$divider-rgb}, calc(#{$divider-a} * var(--fanui-glass-intensity)));
219
+ }
220
+
221
+ // =============================================================================
222
+ // 全局开关 & 无障碍降级
223
+ // -----------------------------------------------------------------------------
224
+ // 关闭方式同样走「基础参数」:把强度类参数全部归零 / 归原,
225
+ // 于是消费端公式自然算出「不透明表面 + 无模糊 + 无高光 + 无流光」。
226
+ //
227
+ // ★ 注意:本 mixin 只定义规则内容;真正「何时何地」输出在 `glass/_switches.scss`。
228
+ // 因为关闭规则与主题块权重相同,必须最后输出才能赢 —— 详见该文件顶部说明。
229
+ // =============================================================================
230
+
231
+ @mixin fanui-emit-glass-off() {
232
+ --fanui-glass-intensity: 0;
233
+ --fanui-glass-blur-base: 0px;
234
+ --fanui-glass-blur-mode-k: 1;
235
+ --fanui-glass-sat-k: 0%;
236
+ --fanui-glass-bri-k: 0%;
237
+ // 底色 = 当前模式的 surface(实体)
238
+ --fanui-glass-tint-rgb: var(--fanui-glass-surface-rgb);
239
+ --fanui-glass-tint-base: 1;
240
+ --fanui-glass-tint-k: 0;
241
+ // 关闭水感、镜面与边缘流光
242
+ --fanui-glass-sheen-a: 0;
243
+ --fanui-glass-specular-a: 0;
244
+ --fanui-glass-specular-alpha: 0;
245
+ --fanui-glass-edge-alpha: 0;
246
+ --fanui-glass-edge-hi-a: 0;
247
+ --fanui-glass-edge-lo-a: 0;
248
+ // 描边与分隔线退回主题描边色
249
+ --fanui-glass-border-rgb: var(--fanui-glass-border-solid-rgb);
250
+ --fanui-glass-border-a: 1;
251
+ --fanui-glass-border-k: 0;
252
+ --fanui-glass-divider-rgb: var(--fanui-glass-border-solid-rgb);
253
+ --fanui-glass-divider-a: 1;
254
+ // 阴影退回静态浅阴影;文字投影移除
255
+ --fanui-glass-shadow-a: 0.06;
256
+ --fanui-glass-shadow-k: 0;
257
+ --fanui-glass-inner-hi: 0;
258
+ --fanui-glass-text-shadow: none;
259
+ }
@@ -0,0 +1,111 @@
1
+ // =============================================================================
2
+ // fanUI · 布局容器 (Container)
3
+ // -----------------------------------------------------------------------------
4
+ // .fanui-container 固定最大宽度容器(随断点变化)
5
+ // .fanui-container-fluid 100% 宽度容器
6
+ // .fanui-container-<bp> 仅在指定断点及以上变为固定宽度
7
+ // =============================================================================
8
+
9
+ @use "sass:map";
10
+ @use "../functions" as fn;
11
+ @use "../variables" as v;
12
+ @use "../mixins" as mx;
13
+
14
+ .fanui-container {
15
+ @include mx.fanui-container();
16
+ }
17
+
18
+ .fanui-container-fluid {
19
+ @include mx.fanui-container-fluid();
20
+ }
21
+
22
+ // 全宽,无内边距
23
+ .fanui-container-full {
24
+ width: 100%;
25
+ margin-inline-end: auto;
26
+ margin-inline-start: auto;
27
+ }
28
+
29
+ // 断点敏感容器:默认 100%,到达断点后锁定最大宽度
30
+ @each $name, $max in v.$fanui-container-max-widths {
31
+ .fanui-container-#{$name} {
32
+ @include mx.fanui-container-fluid();
33
+
34
+ @include mx.fanui-media($name, min) {
35
+ max-width: $max;
36
+ }
37
+ }
38
+ }
39
+
40
+ // -----------------------------------------------------------------------------
41
+ // 主布局骨架 .fanui-layout
42
+ // -----------------------------------------------------------------------------
43
+
44
+ .fanui-layout {
45
+ display: flex;
46
+ flex-direction: column;
47
+ min-height: 100vh;
48
+
49
+ &__header {
50
+ flex: 0 0 auto;
51
+ z-index: fn.fanui-var("z-sticky", v.$fanui-zindex-sticky);
52
+ }
53
+
54
+ &__body {
55
+ flex: 1 1 auto;
56
+ display: flex;
57
+ min-height: 0;
58
+ }
59
+
60
+ &__aside {
61
+ flex: 0 0 auto;
62
+ width: fn.fanui-var("layout-aside-width", 240px);
63
+ overflow-y: auto;
64
+ }
65
+
66
+ &__main {
67
+ flex: 1 1 auto;
68
+ min-width: 0;
69
+ overflow-x: hidden;
70
+ }
71
+
72
+ &__footer {
73
+ flex: 0 0 auto;
74
+ }
75
+
76
+ // 侧边栏在左侧 / 右侧
77
+ &--aside-end .fanui-layout__aside { order: 2; }
78
+ &--aside-end .fanui-layout__main { order: 1; }
79
+
80
+ // 窄屏:侧边栏折叠为抽屉(仅提供基础行为)
81
+ @include mx.fanui-media-down("md") {
82
+ &__aside {
83
+ width: 100%;
84
+ max-width: none;
85
+ }
86
+
87
+ &--responsive .fanui-layout__body {
88
+ flex-direction: column;
89
+ }
90
+ }
91
+ }
92
+
93
+ // -----------------------------------------------------------------------------
94
+ // 通用盒子辅助
95
+ // -----------------------------------------------------------------------------
96
+
97
+ .fanui-main { flex: 1 1 auto; min-width: 0; }
98
+ .fanui-aside { flex: 0 0 auto; }
99
+ .fanui-section { padding-block: fn.fanui-var("space-8"); }
100
+
101
+ .fanui-sticky-top {
102
+ position: sticky;
103
+ top: 0;
104
+ z-index: fn.fanui-var("z-sticky", v.$fanui-zindex-sticky);
105
+ }
106
+
107
+ .fanui-sticky-bottom {
108
+ position: sticky;
109
+ bottom: 0;
110
+ z-index: fn.fanui-var("z-sticky", v.$fanui-zindex-sticky);
111
+ }
@@ -0,0 +1,164 @@
1
+ // =============================================================================
2
+ // fanUI · Flexbox / 显示 工具类 (Layout Utilities)
3
+ // -----------------------------------------------------------------------------
4
+ // 命名:.fanui-<属性>-<值>[-<断点>]
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. display
14
+ // -----------------------------------------------------------------------------
15
+
16
+ @each $value in (none, block, inline, inline-block, flex, inline-flex, grid, inline-grid, contents, flow-root) {
17
+ .fanui-d-#{$value} { display: $value; }
18
+ }
19
+
20
+ // -----------------------------------------------------------------------------
21
+ // 2. flex-direction / wrap
22
+ // -----------------------------------------------------------------------------
23
+
24
+ .fanui-flex-row { flex-direction: row; }
25
+ .fanui-flex-row-reverse { flex-direction: row-reverse; }
26
+ .fanui-flex-col { flex-direction: column; }
27
+ .fanui-flex-col-reverse { flex-direction: column-reverse; }
28
+
29
+ .fanui-flex-wrap { flex-wrap: wrap; }
30
+ .fanui-flex-wrap-reverse { flex-wrap: wrap-reverse; }
31
+ .fanui-flex-nowrap { flex-wrap: nowrap; }
32
+
33
+ // -----------------------------------------------------------------------------
34
+ // 3. justify-content / align-items / align-content / align-self
35
+ // -----------------------------------------------------------------------------
36
+
37
+ $fanui-justify-map: (
38
+ "start": flex-start,
39
+ "end": flex-end,
40
+ "center": center,
41
+ "between": space-between,
42
+ "around": space-around,
43
+ "evenly": space-evenly,
44
+ "stretch": stretch,
45
+ ) !default;
46
+
47
+ @each $name, $value in $fanui-justify-map {
48
+ .fanui-justify-#{$name} { justify-content: $value; }
49
+ }
50
+
51
+ $fanui-align-map: (
52
+ "start": flex-start,
53
+ "end": flex-end,
54
+ "center": center,
55
+ "baseline": baseline,
56
+ "stretch": stretch,
57
+ ) !default;
58
+
59
+ @each $name, $value in $fanui-align-map {
60
+ .fanui-items-#{$name} { align-items: $value; }
61
+ .fanui-content-#{$name} { align-content: $value; }
62
+ .fanui-self-#{$name} { align-self: $value; }
63
+ }
64
+
65
+ .fanui-place-center { place-items: center; }
66
+ .fanui-place-start { place-items: start; }
67
+ .fanui-place-end { place-items: end; }
68
+
69
+ // -----------------------------------------------------------------------------
70
+ // 4. flex 简写 / grow / shrink / basis
71
+ // -----------------------------------------------------------------------------
72
+
73
+ .fanui-flex-1 { flex: 1 1 0%; }
74
+ .fanui-flex-auto { flex: 1 1 auto; }
75
+ .fanui-flex-initial { flex: 0 1 auto; }
76
+ .fanui-flex-none { flex: none; }
77
+
78
+ .fanui-grow { flex-grow: 1; }
79
+ .fanui-grow-0 { flex-grow: 0; }
80
+ .fanui-shrink { flex-shrink: 1; }
81
+ .fanui-shrink-0 { flex-shrink: 0; }
82
+
83
+ .fanui-basis-auto { flex-basis: auto; }
84
+ .fanui-basis-0 { flex-basis: 0%; }
85
+ .fanui-basis-full { flex-basis: 100%; }
86
+ .fanui-basis-1-2 { flex-basis: 50%; }
87
+ .fanui-basis-1-3 { flex-basis: 33.333333%; }
88
+ .fanui-basis-2-3 { flex-basis: 66.666667%; }
89
+ .fanui-basis-1-4 { flex-basis: 25%; }
90
+ .fanui-basis-3-4 { flex-basis: 75%; }
91
+
92
+ // -----------------------------------------------------------------------------
93
+ // 5. order
94
+ // -----------------------------------------------------------------------------
95
+
96
+ @for $i from 0 through 12 {
97
+ .fanui-order-#{$i} { order: $i; }
98
+ }
99
+ .fanui-order-first { order: -9999; }
100
+ .fanui-order-last { order: 9999; }
101
+
102
+ // -----------------------------------------------------------------------------
103
+ // 6. gap
104
+ // -----------------------------------------------------------------------------
105
+
106
+ @each $key, $value in v.$fanui-spacers-utilities {
107
+ .fanui-gap-#{$key} { gap: $value; }
108
+ .fanui-gap-x-#{$key} { column-gap: $value; }
109
+ .fanui-gap-y-#{$key} { row-gap: $value; }
110
+ }
111
+
112
+ // -----------------------------------------------------------------------------
113
+ // 7. 响应式变体(display / direction / justify / items / gap / order)
114
+ // -----------------------------------------------------------------------------
115
+
116
+ @each $bp, $min in v.$fanui-breakpoints {
117
+ @include mx.fanui-media($bp, min) {
118
+ $infix: fn.fanui-bp-infix($bp);
119
+
120
+ @each $value in (none, block, inline, inline-block, flex, inline-flex, grid, inline-grid) {
121
+ .fanui-d#{$infix}-#{$value} { display: $value; }
122
+ }
123
+
124
+ .fanui-flex#{$infix}-row { flex-direction: row; }
125
+ .fanui-flex#{$infix}-col { flex-direction: column; }
126
+ .fanui-flex#{$infix}-row-reverse { flex-direction: row-reverse; }
127
+ .fanui-flex#{$infix}-col-reverse { flex-direction: column-reverse; }
128
+ .fanui-flex#{$infix}-wrap { flex-wrap: wrap; }
129
+ .fanui-flex#{$infix}-nowrap { flex-wrap: nowrap; }
130
+
131
+ @each $name, $value in $fanui-justify-map {
132
+ .fanui-justify#{$infix}-#{$name} { justify-content: $value; }
133
+ }
134
+ @each $name, $value in $fanui-align-map {
135
+ .fanui-items#{$infix}-#{$name} { align-items: $value; }
136
+ .fanui-self#{$infix}-#{$name} { align-self: $value; }
137
+ }
138
+
139
+ @each $key, $value in v.$fanui-spacers-utilities {
140
+ .fanui-gap#{$infix}-#{$key} { gap: $value; }
141
+ }
142
+
143
+ @for $i from 0 through 12 {
144
+ .fanui-order#{$infix}-#{$i} { order: $i; }
145
+ }
146
+ .fanui-order#{$infix}-first { order: -9999; }
147
+ .fanui-order#{$infix}-last { order: 9999; }
148
+ }
149
+ }
150
+
151
+ // -----------------------------------------------------------------------------
152
+ // 8. 常用组合(语义化快捷类)
153
+ // -----------------------------------------------------------------------------
154
+
155
+ .fanui-center { @include mx.fanui-flex(row, center, center); }
156
+ .fanui-center-col { @include mx.fanui-flex(column, center, center); }
157
+ .fanui-between { @include mx.fanui-flex(row, space-between, center); }
158
+ .fanui-around { @include mx.fanui-flex(row, space-around, center); }
159
+ .fanui-start { @include mx.fanui-flex(row, flex-start, center); }
160
+ .fanui-end { @include mx.fanui-flex(row, flex-end, center); }
161
+ .fanui-stack { @include mx.fanui-flex(column, flex-start, stretch); }
162
+ .fanui-inline-row { @include mx.fanui-inline-flex(row, flex-start, center); }
163
+ .fanui-fill { @include mx.fanui-flex-fill(); }
164
+ .fanui-all-center { @include mx.fanui-flex(row, center, center, nowrap); }