@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
@@ -0,0 +1,180 @@
1
+ // =============================================================================
2
+ // fanUI · 响应式栅格系统 (Grid System)
3
+ // -----------------------------------------------------------------------------
4
+ // 命名规范:
5
+ // .fanui-row 行(flex 容器 + 负外边距中和列的内边距)
6
+ // .fanui-col 等分列(自动均分剩余空间)
7
+ // .fanui-col-<n> 占 n/12 列(n = 1..12)
8
+ // .fanui-col-<bp>-<n> 指定断点起生效(bp = sm|md|lg|xl|xxl)
9
+ // .fanui-col-<bp>-auto 内容自适应宽度
10
+ // .fanui-offset-<bp>-<n> 向右偏移 n 列
11
+ // .fanui-order-<bp>-<n> 排序(n = 0..12)
12
+ // .fanui-g-<n> / .fanui-gx-<n> / .fanui-gy-<n> 行/列间距
13
+ // 断点采用移动优先:xs(0) < sm(576) < md(768) < lg(992) < xl(1200) < xxl(1400)
14
+ // =============================================================================
15
+
16
+ @use "sass:map";
17
+ @use "sass:list";
18
+ @use "sass:math";
19
+ @use "../functions" as fn;
20
+ @use "../variables" as v;
21
+ @use "../mixins" as mx;
22
+
23
+ // -----------------------------------------------------------------------------
24
+ // 1. 行 Row
25
+ // -----------------------------------------------------------------------------
26
+
27
+ .fanui-row {
28
+ @include mx.fanui-make-row();
29
+ }
30
+
31
+ // 列数为 0 时取消内边距(常用于嵌套全宽)
32
+ .fanui-row--no-gutters {
33
+ --fanui-gutter-x: 0;
34
+ --fanui-gutter-y: 0;
35
+ }
36
+
37
+ .fanui-row--inline {
38
+ display: inline-flex;
39
+ }
40
+
41
+ // -----------------------------------------------------------------------------
42
+ // 2. 基础列 Col
43
+ // -----------------------------------------------------------------------------
44
+
45
+ .fanui-col {
46
+ flex: 1 0 0%;
47
+ min-width: 0;
48
+ }
49
+
50
+ .fanui-col-auto {
51
+ flex: 0 0 auto;
52
+ width: auto;
53
+ }
54
+
55
+ // -----------------------------------------------------------------------------
56
+ // 3. 固定列宽 .fanui-col-<n>
57
+ // -----------------------------------------------------------------------------
58
+
59
+ @for $i from 1 through v.$fanui-grid-columns {
60
+ .fanui-col-#{$i} {
61
+ flex: 0 0 auto;
62
+ width: fn.fanui-percentage($i, v.$fanui-grid-columns);
63
+ max-width: 100%;
64
+ }
65
+ }
66
+
67
+ // 整行独占
68
+ .fanui-col-12 { flex: 0 0 auto; width: 100%; }
69
+
70
+ // -----------------------------------------------------------------------------
71
+ // 4. 响应式列 .fanui-col-<bp>-<n>
72
+ // -----------------------------------------------------------------------------
73
+
74
+ @each $bp, $min in v.$fanui-breakpoints {
75
+ @include mx.fanui-media($bp, min) {
76
+ $infix: fn.fanui-bp-infix($bp);
77
+
78
+ .fanui-col#{$infix} {
79
+ flex: 1 0 0%;
80
+ min-width: 0;
81
+ }
82
+
83
+ .fanui-col#{$infix}-auto {
84
+ flex: 0 0 auto;
85
+ width: auto;
86
+ max-width: 100%;
87
+ }
88
+
89
+ @for $i from 1 through v.$fanui-grid-columns {
90
+ .fanui-col#{$infix}-#{$i} {
91
+ flex: 0 0 auto;
92
+ width: fn.fanui-percentage($i, v.$fanui-grid-columns);
93
+ max-width: 100%;
94
+ }
95
+ }
96
+
97
+ // 偏移
98
+ @for $i from 0 through (v.$fanui-grid-columns - 1) {
99
+ @if $i == 0 {
100
+ .fanui-offset#{$infix}-0 { margin-inline-start: 0; }
101
+ } @else {
102
+ .fanui-offset#{$infix}-#{$i} {
103
+ margin-inline-start: fn.fanui-percentage($i, v.$fanui-grid-columns);
104
+ }
105
+ }
106
+ }
107
+
108
+ // 排序
109
+ @for $i from 0 through v.$fanui-grid-columns {
110
+ .fanui-order#{$infix}-#{$i} { order: $i; }
111
+ }
112
+ .fanui-order#{$infix}-first { order: -1; }
113
+ .fanui-order#{$infix}-last { order: v.$fanui-grid-columns + 1; }
114
+ }
115
+ }
116
+
117
+ // -----------------------------------------------------------------------------
118
+ // 5. 行间距 / 列间距(gutter)
119
+ // -----------------------------------------------------------------------------
120
+
121
+ $fanui-gutter-steps: (0: 0, 1: 4px, 2: 8px, 3: 12px, 4: 16px, 5: 20px, 6: 24px, 8: 32px, 10: 40px) !default;
122
+
123
+ @each $key, $value in $fanui-gutter-steps {
124
+ .fanui-g#{$key} { --fanui-gutter-x: #{$value}; --fanui-gutter-y: #{$value}; }
125
+ .fanui-gx#{$key} { --fanui-gutter-x: #{$value}; }
126
+ .fanui-gy#{$key} { --fanui-gutter-y: #{$value}; }
127
+ }
128
+
129
+ // 响应式 gutter
130
+ @each $bp, $min in v.$fanui-breakpoints {
131
+ @include mx.fanui-media($bp, min) {
132
+ $infix: fn.fanui-bp-infix($bp);
133
+
134
+ @each $key, $value in $fanui-gutter-steps {
135
+ .fanui-g#{$infix}-#{$key} { --fanui-gutter-x: #{$value}; --fanui-gutter-y: #{$value}; }
136
+ .fanui-gx#{$infix}-#{$key} { --fanui-gutter-x: #{$value}; }
137
+ .fanui-gy#{$infix}-#{$key} { --fanui-gutter-y: #{$value}; }
138
+ }
139
+ }
140
+ }
141
+
142
+ // -----------------------------------------------------------------------------
143
+ // 6. CSS Grid 工具(独立于 12 栅格,用于卡片瀑布流等)
144
+ // -----------------------------------------------------------------------------
145
+
146
+ .fanui-grid {
147
+ display: grid;
148
+ gap: fn.fanui-var("space-4");
149
+ }
150
+
151
+ @for $i from 1 through 12 {
152
+ .fanui-grid-cols-#{$i} {
153
+ grid-template-columns: repeat(#{$i}, minmax(0, 1fr));
154
+ }
155
+ }
156
+
157
+ // 自适应列(auto-fit + minmax),无需媒体查询
158
+ .fanui-grid-auto-xs { @include mx.fanui-grid-auto(120px); }
159
+ .fanui-grid-auto-sm { @include mx.fanui-grid-auto(180px); }
160
+ .fanui-grid-auto-md { @include mx.fanui-grid-auto(240px); }
161
+ .fanui-grid-auto-lg { @include mx.fanui-grid-auto(300px); }
162
+ .fanui-grid-auto-xl { @include mx.fanui-grid-auto(380px); }
163
+
164
+ @each $bp, $min in v.$fanui-breakpoints {
165
+ @include mx.fanui-media($bp, min) {
166
+ $infix: fn.fanui-bp-infix($bp);
167
+
168
+ @for $i from 1 through 12 {
169
+ .fanui-grid-cols#{$infix}-#{$i} {
170
+ grid-template-columns: repeat(#{$i}, minmax(0, 1fr));
171
+ }
172
+ }
173
+
174
+ .fanui-grid-span#{$infix}-full { grid-column: 1 / -1; }
175
+ @for $i from 1 through 12 {
176
+ .fanui-grid-span#{$infix}-#{$i} { grid-column: span #{$i} / span #{$i}; }
177
+ .fanui-grid-rows#{$infix}-#{$i} { grid-row: span #{$i} / span #{$i}; }
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,201 @@
1
+ // =============================================================================
2
+ // fanUI · 主题色令牌输出层 (Accent Roles)
3
+ // -----------------------------------------------------------------------------
4
+ // 本层负责把「12 套主题色」翻译成一整套 CSS 自定义属性,并处理三种作用域:
5
+ //
6
+ // 1. 全局默认 :root → cyan(可配置)
7
+ // 2. 全局显式切换 <html data-fanui-accent="indigo">
8
+ // 3. 局部作用域 <section data-fanui-accent="rose"> → 子树内换色不污染全局
9
+ // <div class="fanui-accent-rose"> → 等价的类名写法
10
+ //
11
+ // 深浅模式与主题色是正交的两条轴:
12
+ // 浅色 + cyan / 深色 + cyan / 浅色 + purple / 深色 + purple … 24 种组合全部覆盖。
13
+ //
14
+ // 输出的令牌清单(每个角色 name 都完整产出,全组件统一引用这些名字):
15
+ // --fanui-<name> --fanui-<name>-fg --fanui-<name>-hover
16
+ // --fanui-<name>-active --fanui-<name>-vivid --fanui-<name>-soft
17
+ // --fanui-<name>-soft-2 --fanui-<name>-border --fanui-<name>-ink
18
+ // --fanui-<name>-ring --fanui-<name>-glow --fanui-<name>-grad-a/b
19
+ // --fanui-<name>-50…950 (原始色阶,随主题色一起重映射)
20
+ // =============================================================================
21
+
22
+ @use "sass:map";
23
+ @use "sass:list";
24
+ @use "../functions" as fn;
25
+ @use "../variables" as v;
26
+ @use "../mixins" as mx;
27
+ @use "palettes" as pal;
28
+
29
+ // -----------------------------------------------------------------------------
30
+ // 1. 主题色 → 令牌
31
+ // -----------------------------------------------------------------------------
32
+
33
+ /// 输出一套主题色(主色 + 和声副色 + 品牌渐变 + 极光色)在指定模式下的全部令牌。
34
+ ///
35
+ /// @param $accent 主题色 key(cyan / sky / blue / …)
36
+ /// @param $mode light | dark
37
+ @mixin fanui-emit-accent-theme($accent, $mode: light) {
38
+ $pal: pal.fanui-accent-palette($accent);
39
+ $secondary: pal.fanui-accent-meta($accent, "secondary");
40
+ $sec-pal: pal.fanui-accent-palette($secondary);
41
+
42
+ $vivid-tone: 500;
43
+ @if $mode == dark {
44
+ $vivid-tone: 400;
45
+ }
46
+
47
+ $p-vivid: map.get($pal, $vivid-tone);
48
+ $s-vivid: map.get($sec-pal, $vivid-tone);
49
+
50
+ // ---- 主色(所有组件的默认品牌色)--------------------------------------
51
+ @include mx.fanui-emit-accent-roles("primary", $pal, $mode);
52
+
53
+ // ---- 和声副色(图表第二序列 / 装饰 / 强调)----------------------------
54
+ @include mx.fanui-emit-accent-roles("accent", $sec-pal, $mode);
55
+
56
+ // ---- 品牌渐变 & 极光色(官网 Hero、卡片高光、图表渐变共用)------------
57
+ --fanui-brand-grad-a: var(--fanui-primary-vivid);
58
+ --fanui-brand-grad-b: var(--fanui-accent-vivid);
59
+ --fanui-brand-grad: linear-gradient(120deg, var(--fanui-primary-vivid), var(--fanui-accent-vivid));
60
+ --fanui-brand-grad-soft: linear-gradient(
61
+ 120deg,
62
+ #{fn.fanui-alpha($p-vivid, 0.16)},
63
+ #{fn.fanui-alpha($s-vivid, 0.14)}
64
+ );
65
+ --fanui-brand-aura-a: #{fn.fanui-alpha($p-vivid, 0.38)};
66
+ --fanui-brand-aura-b: #{fn.fanui-alpha($s-vivid, 0.30)};
67
+ --fanui-brand-name: "#{$accent}";
68
+ }
69
+
70
+ // -----------------------------------------------------------------------------
71
+ // 2. 全局默认(浅色)
72
+ // -----------------------------------------------------------------------------
73
+
74
+ :root {
75
+ @include fanui-emit-accent-theme(v.$fanui-accent-default, light);
76
+ }
77
+
78
+ // -----------------------------------------------------------------------------
79
+ // 3. 12 套主题色 × 浅色模式
80
+ // -----------------------------------------------------------------------------
81
+ // 同时支持属性写法与类名写法,便于「子树局部换色」:
82
+ // <section data-fanui-accent="rose">…</section>
83
+ // <div class="fanui-accent-rose">…</div>
84
+
85
+ @if v.$fanui-enable-accent-themes {
86
+ @each $name, $config in pal.$fanui-accents {
87
+ [data-fanui-accent="#{$name}"],
88
+ .fanui-accent-#{$name} {
89
+ @include fanui-emit-accent-theme($name, light);
90
+ }
91
+ }
92
+ }
93
+
94
+ // -----------------------------------------------------------------------------
95
+ // 4. 全局默认(深色)
96
+ // -----------------------------------------------------------------------------
97
+
98
+ [data-fanui-theme="dark"],
99
+ :root[data-fanui-theme="dark"] {
100
+ @include fanui-emit-accent-theme(v.$fanui-accent-default, dark);
101
+ }
102
+
103
+ // -----------------------------------------------------------------------------
104
+ // 5. 12 套主题色 × 深色模式
105
+ // -----------------------------------------------------------------------------
106
+ // 选择器组合保证三层覆盖关系正确(全局默认 < 显式主题色 < 深色 + 显式主题色):
107
+ // [data-fanui-theme="dark"][data-fanui-accent="x"] 同元素
108
+ // [data-fanui-theme="dark"] [data-fanui-accent="x"] 祖先为深色
109
+ // [data-fanui-theme="dark"] .fanui-accent-x 祖先为深色(类名写法)
110
+
111
+ @if v.$fanui-enable-accent-themes {
112
+ @each $name, $config in pal.$fanui-accents {
113
+ [data-fanui-theme="dark"][data-fanui-accent="#{$name}"],
114
+ [data-fanui-theme="dark"] [data-fanui-accent="#{$name}"],
115
+ [data-fanui-theme="dark"] .fanui-accent-#{$name} {
116
+ @include fanui-emit-accent-theme($name, dark);
117
+ }
118
+ }
119
+ }
120
+
121
+ // -----------------------------------------------------------------------------
122
+ // 6. 跟随系统(auto)
123
+ // -----------------------------------------------------------------------------
124
+
125
+ @media (prefers-color-scheme: dark) {
126
+ [data-fanui-theme="auto"],
127
+ :root[data-fanui-theme="auto"] {
128
+ @include fanui-emit-accent-theme(v.$fanui-accent-default, dark);
129
+ }
130
+
131
+ @if v.$fanui-enable-accent-themes {
132
+ @each $name, $config in pal.$fanui-accents {
133
+ [data-fanui-theme="auto"][data-fanui-accent="#{$name}"],
134
+ [data-fanui-theme="auto"] [data-fanui-accent="#{$name}"],
135
+ [data-fanui-theme="auto"] .fanui-accent-#{$name} {
136
+ @include fanui-emit-accent-theme($name, dark);
137
+ }
138
+ }
139
+ }
140
+ }
141
+
142
+ // -----------------------------------------------------------------------------
143
+ // 7. 语义色角色(success / warning / danger / info)
144
+ // -----------------------------------------------------------------------------
145
+ // 它们不随主题色变化,但使用与主题色完全相同的令牌口径。
146
+ // 实心色取 700 阶以保证白字达到 WCAG AA;500/600 阶保留为 -vivid 供装饰使用。
147
+
148
+ :root {
149
+ @each $name in v.$fanui-semantic-names {
150
+ $pal: map.get(v.$fanui-palette, $name);
151
+ @include mx.fanui-emit-color-roles(
152
+ $name,
153
+ map.get($pal, 700),
154
+ map.get($pal, 500),
155
+ map.get($pal, 600),
156
+ map.get($pal, 50),
157
+ map.get($pal, 100),
158
+ map.get($pal, 200),
159
+ map.get($pal, 800),
160
+ light
161
+ );
162
+ }
163
+ }
164
+
165
+ [data-fanui-theme="dark"],
166
+ :root[data-fanui-theme="dark"] {
167
+ @each $name in v.$fanui-semantic-names {
168
+ $pal: map.get(v.$fanui-palette, $name);
169
+ @include mx.fanui-emit-color-roles(
170
+ $name,
171
+ map.get($pal, 400),
172
+ map.get($pal, 400),
173
+ map.get($pal, 300),
174
+ null,
175
+ null,
176
+ null,
177
+ map.get($pal, 200),
178
+ dark
179
+ );
180
+ }
181
+ }
182
+
183
+ @media (prefers-color-scheme: dark) {
184
+ [data-fanui-theme="auto"],
185
+ :root[data-fanui-theme="auto"] {
186
+ @each $name in v.$fanui-semantic-names {
187
+ $pal: map.get(v.$fanui-palette, $name);
188
+ @include mx.fanui-emit-color-roles(
189
+ $name,
190
+ map.get($pal, 400),
191
+ map.get($pal, 400),
192
+ map.get($pal, 300),
193
+ null,
194
+ null,
195
+ null,
196
+ map.get($pal, 200),
197
+ dark
198
+ );
199
+ }
200
+ }
201
+ }
@@ -0,0 +1,180 @@
1
+ // =============================================================================
2
+ // fanUI · 12 套主题色(Accent Themes)
3
+ // -----------------------------------------------------------------------------
4
+ // 每套主题包含:11 阶调色板(50 → 950)+ 元数据(名称、推荐配对副色、气质量表)
5
+ //
6
+ // 设计原则
7
+ // 1. 色相覆盖完整色环:青 → 天蓝 → 蓝 → 靛 → 紫罗兰 → 紫 → 粉 → 玫红 → 赤 → 橙 → 翡翠 → 青碧
8
+ // 2. 同一套阶差体系(50/100…900/950),保证明度节奏一致,任意主题互换后版式不塌
9
+ // 3. 不硬编码「品牌主色阶」:由 fanui-emit-accent-roles() 按 WCAG 对比度自动择优,
10
+ // 因此换主题、加主题都不需要人工逐个调校颜色
11
+ // 4. 每套主题配一个「和声副色」(secondary),用于品牌渐变、图表第二序列、装饰元素,
12
+ // 避免用户自己乱搭导致色彩失衡
13
+ //
14
+ // 默认主题:cyan(青)—— 理由见 docs/DESIGN-SYSTEM.md「默认主题色论证」
15
+ // =============================================================================
16
+
17
+ @use "sass:map";
18
+
19
+ /// 默认主题色
20
+ $fanui-accent-default: "cyan" !default;
21
+
22
+ /// 12 套主题色定义
23
+ /// @prop label 中文名(用于主题面板展示)
24
+ /// @prop hue 代表色相角(用于派生极光背景、光晕等装饰色)
25
+ /// @prop palette 11 阶调色板
26
+ /// @prop secondary 和声副色(另一个 accent 的 key)
27
+ /// @prop vibe 气质标签(B 端 / C 端适配建议)
28
+ $fanui-accents: (
29
+ "cyan": (
30
+ "label": "青",
31
+ "en": "Cyan",
32
+ "hue": 189,
33
+ "vibe": "科技 · 清爽",
34
+ "secondary": "violet",
35
+ "palette": (
36
+ 50: #ecfeff, 100: #cffafe, 200: #a5f3fc, 300: #67e8f9, 400: #22d3ee,
37
+ 500: #06b6d4, 600: #0891b2, 700: #0e7490, 800: #155e75, 900: #164e63, 950: #083344
38
+ )
39
+ ),
40
+ "sky": (
41
+ "label": "天蓝",
42
+ "en": "Sky",
43
+ "hue": 199,
44
+ "vibe": "轻盈 · 开放",
45
+ "secondary": "violet",
46
+ "palette": (
47
+ 50: #f0f9ff, 100: #e0f2fe, 200: #bae6fd, 300: #7dd3fc, 400: #38bdf8,
48
+ 500: #0ea5e9, 600: #0284c7, 700: #0369a1, 800: #075985, 900: #0c4a6e, 950: #082f49
49
+ )
50
+ ),
51
+ "blue": (
52
+ "label": "经典蓝",
53
+ "en": "Blue",
54
+ "hue": 217,
55
+ "vibe": "稳健 · 通用",
56
+ "secondary": "cyan",
57
+ "palette": (
58
+ 50: #eff6ff, 100: #dbeafe, 200: #bfdbfe, 300: #93c5fd, 400: #60a5fa,
59
+ 500: #3b82f6, 600: #2563eb, 700: #1d4ed8, 800: #1e40af, 900: #1e3a8a, 950: #172554
60
+ )
61
+ ),
62
+ "indigo": (
63
+ "label": "靛蓝",
64
+ "en": "Indigo",
65
+ "hue": 239,
66
+ "vibe": "专业 · 前沿",
67
+ "secondary": "cyan",
68
+ "palette": (
69
+ 50: #eef2ff, 100: #e0e7ff, 200: #c7d2fe, 300: #a5b4fc, 400: #818cf8,
70
+ 500: #6366f1, 600: #4f46e5, 700: #4338ca, 800: #3730a3, 900: #312e81, 950: #1e1b4b
71
+ )
72
+ ),
73
+ "violet": (
74
+ "label": "紫罗兰",
75
+ "en": "Violet",
76
+ "hue": 258,
77
+ "vibe": "创意 · 智能",
78
+ "secondary": "cyan",
79
+ "palette": (
80
+ 50: #f5f3ff, 100: #ede9fe, 200: #ddd6fe, 300: #c4b5fd, 400: #a78bfa,
81
+ 500: #8b5cf6, 600: #7c3aed, 700: #6d28d9, 800: #5b21b6, 900: #4c1d95, 950: #2e1065
82
+ )
83
+ ),
84
+ "purple": (
85
+ "label": "紫",
86
+ "en": "Purple",
87
+ "hue": 272,
88
+ "vibe": "艺术 · 张扬",
89
+ "secondary": "pink",
90
+ "palette": (
91
+ 50: #faf5ff, 100: #f3e8ff, 200: #e9d5ff, 300: #d8b4fe, 400: #c084fc,
92
+ 500: #a855f7, 600: #9333ea, 700: #7e22ce, 800: #6b21a8, 900: #581c87, 950: #3b0764
93
+ )
94
+ ),
95
+ "pink": (
96
+ "label": "品粉",
97
+ "en": "Pink",
98
+ "hue": 330,
99
+ "vibe": "年轻 · 潮流",
100
+ "secondary": "violet",
101
+ "palette": (
102
+ 50: #fdf2f8, 100: #fce7f3, 200: #fbcfe8, 300: #f9a8d4, 400: #f472b6,
103
+ 500: #ec4899, 600: #db2777, 700: #be185d, 800: #9d174d, 900: #831843, 950: #500724
104
+ )
105
+ ),
106
+ "rose": (
107
+ "label": "玫红",
108
+ "en": "Rose",
109
+ "hue": 350,
110
+ "vibe": "浪漫 · 亲和",
111
+ "secondary": "orange",
112
+ "palette": (
113
+ 50: #fff1f2, 100: #ffe4e6, 200: #fecdd3, 300: #fda4af, 400: #fb7185,
114
+ 500: #f43f5e, 600: #e11d48, 700: #be123c, 800: #9f1239, 900: #881337, 950: #4c0519
115
+ )
116
+ ),
117
+ "red": (
118
+ "label": "赤红",
119
+ "en": "Red",
120
+ "hue": 0,
121
+ "vibe": "强烈 · 行动",
122
+ "secondary": "rose",
123
+ "palette": (
124
+ 50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171,
125
+ 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a
126
+ )
127
+ ),
128
+ "orange": (
129
+ "label": "橙",
130
+ "en": "Orange",
131
+ "hue": 25,
132
+ "vibe": "活力 · 温暖",
133
+ "secondary": "pink",
134
+ "palette": (
135
+ 50: #fff7ed, 100: #ffedd5, 200: #fed7aa, 300: #fdba74, 400: #fb923c,
136
+ 500: #f97316, 600: #ea580c, 700: #c2410c, 800: #9a3412, 900: #7c2d12, 950: #431407
137
+ )
138
+ ),
139
+ "emerald": (
140
+ "label": "翡翠",
141
+ "en": "Emerald",
142
+ "hue": 160,
143
+ "vibe": "成长 · 健康",
144
+ "secondary": "cyan",
145
+ "palette": (
146
+ 50: #ecfdf5, 100: #d1fae5, 200: #a7f3d0, 300: #6ee7b7, 400: #34d399,
147
+ 500: #10b981, 600: #059669, 700: #047857, 800: #065f46, 900: #064e3b, 950: #022c22
148
+ )
149
+ ),
150
+ "teal": (
151
+ "label": "青碧",
152
+ "en": "Teal",
153
+ "hue": 173,
154
+ "vibe": "沉静 · 高效",
155
+ "secondary": "emerald",
156
+ "palette": (
157
+ 50: #f0fdfa, 100: #ccfbf1, 200: #99f6e4, 300: #5eead4, 400: #2dd4bf,
158
+ 500: #14b8a6, 600: #0d9488, 700: #0f766e, 800: #115e59, 900: #134e4a, 950: #042f2e
159
+ )
160
+ )
161
+ ) !default;
162
+
163
+ /// 主题色 key 列表(顺序即主题面板展示顺序)
164
+ $fanui-accent-names: map.keys($fanui-accents) !default;
165
+
166
+ /// 取某主题色的调色板。
167
+ @function fanui-accent-palette($name) {
168
+ @if not map.has-key($fanui-accents, $name) {
169
+ @error "fanUI: 未知主题色 `#{$name}`,可用值:#{$fanui-accent-names}。";
170
+ }
171
+ @return map.get(map.get($fanui-accents, $name), "palette");
172
+ }
173
+
174
+ /// 取某主题色的元数据字段。
175
+ @function fanui-accent-meta($name, $key) {
176
+ @if not map.has-key($fanui-accents, $name) {
177
+ @error "fanUI: 未知主题色 `#{$name}`。";
178
+ }
179
+ @return map.get(map.get($fanui-accents, $name), $key);
180
+ }
@@ -0,0 +1,104 @@
1
+ // =============================================================================
2
+ // fanUI · 边框 / 圆角 工具类 (Borders)
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-border { border: fn.fanui-var("border-width", 1px) solid fn.fanui-var("color-border"); }
15
+ .fanui-border-0 { border-width: 0; }
16
+ .fanui-border-top { border-top: 1px solid fn.fanui-var("color-border"); }
17
+ .fanui-border-right { border-inline-end: 1px solid fn.fanui-var("color-border"); }
18
+ .fanui-border-bottom { border-bottom: 1px solid fn.fanui-var("color-border"); }
19
+ .fanui-border-left { border-inline-start: 1px solid fn.fanui-var("color-border"); }
20
+ .fanui-border-top-0 { border-top-width: 0; }
21
+ .fanui-border-right-0 { border-inline-end-width: 0; }
22
+ .fanui-border-bottom-0 { border-bottom-width: 0; }
23
+ .fanui-border-left-0 { border-inline-start-width: 0; }
24
+
25
+ .fanui-border-thick { border-width: 2px; }
26
+ .fanui-border-dashed { border-style: dashed; }
27
+ .fanui-border-dotted { border-style: dotted; }
28
+ .fanui-border-none { border: none; }
29
+
30
+ // -----------------------------------------------------------------------------
31
+ // 2. 边框颜色
32
+ // -----------------------------------------------------------------------------
33
+
34
+ .fanui-border-default { border-color: fn.fanui-var("color-border"); }
35
+ .fanui-border-subtle { border-color: fn.fanui-var("color-border-subtle"); }
36
+ .fanui-border-strong { border-color: fn.fanui-var("color-border-strong"); }
37
+ .fanui-border-primary { border-color: fn.fanui-var("primary"); }
38
+ .fanui-border-current { border-color: currentColor; }
39
+ .fanui-border-transparent { border-color: transparent; }
40
+
41
+ @each $name, $color in v.$fanui-theme-colors {
42
+ .fanui-border-#{$name} { border-color: fn.fanui-var("#{$name}"); }
43
+ }
44
+
45
+ // -----------------------------------------------------------------------------
46
+ // 3. 圆角
47
+ // -----------------------------------------------------------------------------
48
+
49
+ @each $name, $value in v.$fanui-radii {
50
+ .fanui-rounded-#{$name} {
51
+ border-radius: fn.fanui-var("radius-#{$name}", $value);
52
+ }
53
+ }
54
+
55
+ .fanui-rounded { border-radius: fn.fanui-var("radius-base"); }
56
+ .fanui-rounded-full { border-radius: 9999px; }
57
+
58
+ .fanui-rounded-top { border-radius: fn.fanui-var("radius-base") fn.fanui-var("radius-base") 0 0; }
59
+ .fanui-rounded-bottom { border-radius: 0 0 fn.fanui-var("radius-base") fn.fanui-var("radius-base"); }
60
+ .fanui-rounded-start { border-radius: fn.fanui-var("radius-base") 0 0 fn.fanui-var("radius-base"); }
61
+ .fanui-rounded-end { border-radius: 0 fn.fanui-var("radius-base") fn.fanui-var("radius-base") 0; }
62
+
63
+ // -----------------------------------------------------------------------------
64
+ // 4. 分割线 / 分隔符
65
+ // -----------------------------------------------------------------------------
66
+
67
+ .fanui-divider {
68
+ height: 1px;
69
+ margin: fn.fanui-var("space-4") 0;
70
+ background-color: fn.fanui-var("color-border");
71
+ border: 0;
72
+ }
73
+
74
+ .fanui-divider--vertical {
75
+ width: 1px;
76
+ height: auto;
77
+ min-height: 1em;
78
+ margin: 0 fn.fanui-var("space-3");
79
+ align-self: stretch;
80
+ }
81
+
82
+ .fanui-divider--dashed {
83
+ background: none;
84
+ border-top: 1px dashed fn.fanui-var("color-border");
85
+ }
86
+
87
+ // 带文字的分割线
88
+ .fanui-divider-text {
89
+ display: flex;
90
+ align-items: center;
91
+ gap: fn.fanui-var("space-3");
92
+ margin: fn.fanui-var("space-4") 0;
93
+ font-size: fn.fanui-var("font-size-sm");
94
+ color: fn.fanui-var("color-text-subtle");
95
+ white-space: nowrap;
96
+
97
+ &::before,
98
+ &::after {
99
+ content: "";
100
+ flex: 1 1 auto;
101
+ height: 1px;
102
+ background-color: fn.fanui-var("color-border");
103
+ }
104
+ }