@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
package/README.md
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# fanUI v2.1
|
|
2
|
+
|
|
3
|
+
> fanUI:一套 UI 设计系统,内置 **12 套可在运行时切换的主题配色**(默认 cyan)、**液态玻璃质感**(强度可调 + 总开关)、**明暗双模式**;适配官网、博客与 B 端控制台场景。
|
|
4
|
+
> 下载即可使用:可以直接用 `<script>` / `<link>` 引入编译产物(不需要构建工具),也可以装进项目走 npm + 构建(ESM / SCSS 按需)。纯 CSS 变量驱动、SCSS 可配置。
|
|
5
|
+
|
|
6
|
+
> 📗 **调用文档(零基础开箱即用:引入方式 / React·Vue 兼容 / JS API 全参数参考)见 [USAGE.md](./USAGE.md)**。
|
|
7
|
+
> 📘 完整设计规范(主题轴 / 玻璃材质 / 自动可达性算法 / 扩展指南)见 **[DESIGN-SYSTEM.md](./DESIGN-SYSTEM.md)**。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. 目录结构
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
fanUI/
|
|
15
|
+
├── package.json # 构建脚本与元信息
|
|
16
|
+
├── README.md # 本文档
|
|
17
|
+
├── DESIGN-SYSTEM.md # 设计系统规范(v2 核心)
|
|
18
|
+
├── theme-audit.md # 对比度审计报告(60/60 通过)
|
|
19
|
+
├── src/
|
|
20
|
+
│ ├── fanui.scss # 主入口(按顺序聚合全部模块)
|
|
21
|
+
│ ├── fanui.js # 可选:交互运行时(主题中枢/工作台/组件交互),无外部依赖
|
|
22
|
+
│ ├── _functions.scss # 工具函数(含对比度/自动选阶色彩数学)
|
|
23
|
+
│ ├── _variables.scss # SCSS 设计变量($fanui-*)
|
|
24
|
+
│ ├── _mixins.scss # 混合宏(含 fanui-liquid-glass / 主题发射器)
|
|
25
|
+
│ ├── _tokens.scss # 非主题色令牌 → CSS 自定义属性
|
|
26
|
+
│ ├── themes/ # ★ v2 主题系统
|
|
27
|
+
│ │ ├── _palettes.scss # 12 套主题定义(数据与逻辑分离)
|
|
28
|
+
│ │ └── _accents.scss # 主题发射器:12 色 × 明暗 × auto 全量输出
|
|
29
|
+
│ ├── glass/ # ★ v2 液态玻璃
|
|
30
|
+
│ │ └── _tokens.scss # 玻璃令牌族(强度/预设/模式感知)
|
|
31
|
+
│ ├── base/ # 基础层
|
|
32
|
+
│ │ ├── _reset.scss # CSS 重置 / Normalize
|
|
33
|
+
│ │ ├── _typography.scss # 字体排版体系
|
|
34
|
+
│ │ └── _animations.scss # 关键帧与动效工具类
|
|
35
|
+
│ ├── layout/ # 布局层
|
|
36
|
+
│ │ ├── _container.scss # 容器 / 主布局骨架
|
|
37
|
+
│ │ ├── _grid.scss # 12 列响应式栅格 + CSS Grid 工具
|
|
38
|
+
│ │ └── _flex.scss # Flexbox / 显示 工具类
|
|
39
|
+
│ ├── components/ # 组件层
|
|
40
|
+
│ │ ├── _button.scss # 按钮 / 按钮组
|
|
41
|
+
│ │ ├── _form.scss # 表单 / 输入框 / 文本域
|
|
42
|
+
│ │ ├── _choice.scss # 选择器 / 复选 / 单选 / 开关 / 分段
|
|
43
|
+
│ │ ├── _card.scss # 卡片 / 面板 / 统计卡
|
|
44
|
+
│ │ ├── _table.scss # 表格
|
|
45
|
+
│ │ ├── _badge.scss # 徽标 / 标签 / 状态点
|
|
46
|
+
│ │ ├── _alert.scss # 警告框 / Toast
|
|
47
|
+
│ │ ├── _nav.scss # 导航栏 / 侧边栏 / 面包屑 / 菜单
|
|
48
|
+
│ │ ├── _tabs.scss # 选项卡 / 手风琴
|
|
49
|
+
│ │ ├── _overlay.scss # 模态框 / 抽屉 / 下拉 / 气泡
|
|
50
|
+
│ │ ├── _feedback.scss # 进度 / 加载 / 骨架屏 / 空状态
|
|
51
|
+
│ │ ├── _data.scss # 头像 / 列表 / 分页 / 步骤条 / 时间线
|
|
52
|
+
│ │ ├── _glass.scss # ★ 玻璃材质 + 5 预设 + 组件玻璃形态
|
|
53
|
+
│ │ ├── _input-plus.scss # ★ 滑块/评分/上传/标签输入/步进器/验证码/色板/联想
|
|
54
|
+
│ │ ├── _interactive.scss # ★ ⌘K 命令面板/Dock 放大/轮播/聚光灯/主题工作台
|
|
55
|
+
│ │ ├── _marketing.scss # ★ Hero/Bento/定价/证言/FAQ 等营销场景
|
|
56
|
+
│ │ ├── _blog.scss # ★ 文章卡/文章版式/目录 scrollspy/评论/订阅
|
|
57
|
+
│ │ └── _dashboard.scss # ★ KPI/柱状图/环形图/看板/通知/筛选栏
|
|
58
|
+
│ └── utilities/ # 工具层(最后输出,保证优先级)
|
|
59
|
+
│ ├── _spacing.scss # 间距
|
|
60
|
+
│ ├── _display.scss # 显示 / 定位 / 溢出 / 层级
|
|
61
|
+
│ ├── _sizing.scss # 尺寸 / 宽高比
|
|
62
|
+
│ ├── _borders.scss # 边框 / 圆角 / 分割线
|
|
63
|
+
│ ├── _effects.scss # 阴影 / 滤镜 / 背景 / 交互
|
|
64
|
+
│ └── _texture.scss # ★ 极光/网格/噪点/渐变描边/流光/涟漪
|
|
65
|
+
├── scripts/
|
|
66
|
+
│ ├── build.cjs # 构建脚本(自动定位 sass)
|
|
67
|
+
│ ├── audit-theme.cjs # 对比度审计 → theme-audit.md
|
|
68
|
+
│ └── verify-demo.cjs # 真实浏览器回归(组合遍历/交互/截图)
|
|
69
|
+
├── dist/ # 编译产物
|
|
70
|
+
│ ├── fanui.css # 已展开(开发用)
|
|
71
|
+
│ ├── fanui.min.css # 已压缩(生产用)
|
|
72
|
+
│ └── fanui.js # JS 运行时(由 src 复制)
|
|
73
|
+
└── demo/
|
|
74
|
+
├── index.html # ★ 场景化演示站:官网/博客/控制台/组件/设计系统 5 场景
|
|
75
|
+
├── components.html # 全组件百科页(令牌/排版/栅格/组件/工具类)
|
|
76
|
+
└── shots/ # 浏览器回归截图(14 张)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 2. 命名规范
|
|
82
|
+
|
|
83
|
+
### 2.1 总原则
|
|
84
|
+
|
|
85
|
+
| 类型 | 前缀 | 示例 |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| CSS 类名 | `.fanui-` | `.fanui-btn`、`.fanui-card__title`、`.fanui-col-md-6` |
|
|
88
|
+
| SCSS 变量 | `$fanui-` | `$fanui-primary`、`$fanui-radius-base` |
|
|
89
|
+
| 工具函数 | `fanui-…()` | `fanui-px2rem()`、`fanui-alpha()`、`fanui-map-deep()` |
|
|
90
|
+
| Mixin | `fanui-…()` | `@include fanui-flex()`、`@include fanui-media()` |
|
|
91
|
+
| CSS 自定义属性 | `--fanui-` | `--fanui-color-text`、`--fanui-space-4` |
|
|
92
|
+
| 状态类 | `.is-` / `.has-` | `.is-active`、`.is-disabled`、`.is-open` |
|
|
93
|
+
| JS API | `FanUI.*` | `FanUI.modal.open()`、`FanUI.toast.success()` |
|
|
94
|
+
|
|
95
|
+
### 2.2 类名结构(BEM 变体)
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
.fanui-block 块
|
|
99
|
+
.fanui-block__element 元素(双下划线)
|
|
100
|
+
.fanui-block--modifier 修饰符(双连字符)
|
|
101
|
+
.fanui-block.is-state 状态(独立类,便于 JS 切换)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2.3 工具类命名
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
.fanui-<属性简写>-<值> .fanui-mt-4 .fanui-text-center .fanui-gap-6
|
|
108
|
+
.fanui-<属性简写>-<断点>-<值> .fanui-mt-md-4 .fanui-flex-lg-col .fanui-order-lg-2
|
|
109
|
+
.fanui-<属性简写><方向>-<值> .fanui-px-6 .fanui-my-auto
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**方向简写**:`t` 上 · `r` 右 · `b` 下 · `l` 左 · `x` 左右 · `y` 上下 · 缺省 四向
|
|
113
|
+
|
|
114
|
+
**断点简写**:`xs(≥0)` · `sm(≥576)` · `md(≥768)` · `lg(≥992)` · `xl(≥1200)` · `xxl(≥1400)`
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 3. 快速开始
|
|
119
|
+
|
|
120
|
+
> 逐步可照做的完整接入说明(含包管理器 / CDN / React 多版本 / Vue2·Vue3 写法)见 **[USAGE.md](./USAGE.md)**;下面是最短路径。
|
|
121
|
+
|
|
122
|
+
### 3.1 直接使用编译产物(不接构建流程)
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<html data-fanui-theme="dark" data-fanui-accent="cyan" data-fanui-glass="on">
|
|
126
|
+
<head>
|
|
127
|
+
<link rel="stylesheet" href="dist/fanui.css">
|
|
128
|
+
</head>
|
|
129
|
+
<body>
|
|
130
|
+
<button class="fanui-btn fanui-btn--primary">主要按钮</button>
|
|
131
|
+
<script src="dist/fanui.js"></script>
|
|
132
|
+
<script>
|
|
133
|
+
FanUI.studio.mount(); // 可选:挂载「主题工作台」悬浮面板
|
|
134
|
+
</script>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 3.2 SCSS 引入(整库 + 可配置)
|
|
140
|
+
|
|
141
|
+
```scss
|
|
142
|
+
// 覆盖默认设计变量(必须在其它 fanui 模块之前 @use)
|
|
143
|
+
@use "@zhang_jifan/fanui/src/fanui" with (
|
|
144
|
+
$fanui-primary: #7c3aed,
|
|
145
|
+
$fanui-radius-base: 8px,
|
|
146
|
+
$fanui-grid-columns: 24,
|
|
147
|
+
$fanui-enable-dark-mode: true
|
|
148
|
+
);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 3.3 按需引入单个模块
|
|
152
|
+
|
|
153
|
+
```scss
|
|
154
|
+
@use "@zhang_jifan/fanui/src/functions" as fn;
|
|
155
|
+
@use "@zhang_jifan/fanui/src/mixins" as mx;
|
|
156
|
+
@use "@zhang_jifan/fanui/src/variables" as v;
|
|
157
|
+
|
|
158
|
+
.my-panel {
|
|
159
|
+
@include mx.fanui-flex(column, flex-start, stretch, nowrap, v.$fanui-spacer);
|
|
160
|
+
padding: fn.fanui-px2rem(24px);
|
|
161
|
+
border-radius: fn.fanui-px2rem(8px);
|
|
162
|
+
color: fn.fanui-var("color-text"); // var(--fanui-color-text)
|
|
163
|
+
background: fn.fanui-alpha(v.$fanui-primary, 0.08);
|
|
164
|
+
|
|
165
|
+
@include mx.fanui-media("md") { // @media (min-width: 768px)
|
|
166
|
+
flex-direction: row;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 4. 工具函数 API(`fanui-*()`)
|
|
174
|
+
|
|
175
|
+
| 函数 | 作用 | 示例 → 结果 |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `fanui-strip-unit($n)` | 去单位 | `fanui-strip-unit(16px)` → `16` |
|
|
178
|
+
| `fanui-px2rem($px,$base)` | px→rem | `fanui-px2rem(24px)` → `1.5rem` |
|
|
179
|
+
| `fanui-rem2px($rem,$base)` | rem→px | `fanui-rem2px(1.5rem)` → `24px` |
|
|
180
|
+
| `fanui-px2em($px,$ctx)` | px→em | `fanui-px2em(14px,16px)` → `0.875em` |
|
|
181
|
+
| `fanui-percentage($a,$b)` | 百分比 | `fanui-percentage(6,12)` → `50%` |
|
|
182
|
+
| `fanui-negate($v)` | 取负 | `fanui-negate(16px)` → `-16px` |
|
|
183
|
+
| `fanui-alpha($c,$a)` | 透明度 | `fanui-alpha(#2563eb,.5)` |
|
|
184
|
+
| `fanui-tint($c,$w)` | 混白变亮 | `fanui-tint(#2563eb,20%)` |
|
|
185
|
+
| `fanui-shade($c,$w)` | 混黑变暗 | `fanui-shade(#2563eb,10%)` |
|
|
186
|
+
| `fanui-luminance($c)` | 感知亮度 | `fanui-luminance(#2563eb)` |
|
|
187
|
+
| `fanui-contrast($c)` | 自动对比色 | `fanui-contrast(#2563eb)` → `#ffffff` |
|
|
188
|
+
| `fanui-mix($a,$b,$t)` | 插值 | `fanui-mix(#000,#fff,.3)` |
|
|
189
|
+
| `fanui-map-deep($m,$k...)` | 深读 map | `fanui-map-deep($palette,"primary",600)` |
|
|
190
|
+
| `fanui-palette($m,$n,$t)` | 读色阶 | `fanui-palette($palette,"danger",500)` |
|
|
191
|
+
| `fanui-var($name,$fb)` | 生成 var() | `fanui-var("radius",6px)` → `var(--fanui-radius,6px)` |
|
|
192
|
+
| `fanui-calc($a,$op,$b)` | 生成 calc() | `fanui-calc("100%","-",24px)` |
|
|
193
|
+
| `fanui-bp-infix($bp)` | 断点中缀 | `fanui-bp-infix("md")` → `-md` |
|
|
194
|
+
|
|
195
|
+
## 5. Mixin API(`@include fanui-*`)
|
|
196
|
+
|
|
197
|
+
**布局**:`fanui-flex()` · `fanui-inline-flex()` · `fanui-center-flex()` · `fanui-flex-item()` · `fanui-flex-fill()` · `fanui-grid()` · `fanui-grid-auto()` · `fanui-container()` · `fanui-container-fluid()` · `fanui-make-row()` · `fanui-make-col()`
|
|
198
|
+
|
|
199
|
+
**尺寸定位**:`fanui-size()` · `fanui-square()` · `fanui-absolute-fill()` · `fanui-abs-center()` · `fanui-fixed-fill()` · `fanui-aspect-ratio()`
|
|
200
|
+
|
|
201
|
+
**响应式**:`fanui-media()` · `fanui-media-down()` · `fanui-media-between()` · `fanui-media-only()` · `fanui-each-breakpoint()` · `fanui-prefers-dark()` · `fanui-motion-safe()`
|
|
202
|
+
|
|
203
|
+
**文本外观**:`fanui-truncate()` · `fanui-font()` · `fanui-text-gradient()` · `fanui-visually-hidden()` · `fanui-placeholder()` · `fanui-clearfix()`
|
|
204
|
+
|
|
205
|
+
**外观**:`fanui-appearance-none()` · `fanui-focus-ring()` · `fanui-elevation()` · `fanui-border()` · `fanui-border-radius()` · `fanui-transition()` · `fanui-disabled()` · `fanui-scrollbar()` · `fanui-gradient()` · `fanui-glass()` · `fanui-pressable()`
|
|
206
|
+
|
|
207
|
+
**组件生成器**:`fanui-button-variant()` · `fanui-button-outline-variant()` · `fanui-button-text-variant()` · `fanui-button-size()` · `fanui-badge-variant()` · `fanui-badge-soft-variant()` · `fanui-alert-variant()` · `fanui-form-control()` · `fanui-form-validation()` · `fanui-card-variant()` · `fanui-interactive-surface()` · `fanui-backdrop()` · `fanui-table-variant()` · `fanui-progress-variant()` · `fanui-switch-variant()`
|
|
208
|
+
|
|
209
|
+
**令牌输出**:`fanui-emit-theme()` · `fanui-emit-palette()` · `fanui-emit-semantic-colors()`
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 6. 设计令牌(CSS 自定义属性)
|
|
214
|
+
|
|
215
|
+
运行时可通过覆盖 `:root` 或任意容器上的变量实现**免编译换肤**:
|
|
216
|
+
|
|
217
|
+
```css
|
|
218
|
+
:root {
|
|
219
|
+
--fanui-primary: #7c3aed; /* 品牌主色 */
|
|
220
|
+
--fanui-radius-base: 8px; /* 全局圆角 */
|
|
221
|
+
--fanui-color-bg: #0b1120; /* 页面底色 */
|
|
222
|
+
--fanui-space-4: 18px; /* 基础间距 */
|
|
223
|
+
--fanui-font-size-base: 15px;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
| 令牌族 | 前缀 | 说明 |
|
|
228
|
+
|---|---|---|
|
|
229
|
+
| 调色板 | `--fanui-{color}-{50…950}` | 6 语义色 + 中性色,各 11 阶 |
|
|
230
|
+
| 语义色 | `--fanui-{name}` / `-hover` / `-active` / `-soft` / `-border` / `-fg` / `-ring` | 由主色派生 |
|
|
231
|
+
| 主题语义 | `--fanui-color-{bg\|surface\|text\|border\|hover\|active\|disabled…}` | 明暗主题自动切换 |
|
|
232
|
+
| 字号 | `--fanui-font-size-{xs…6xl}` | rem 输出 |
|
|
233
|
+
| 行高 | `--fanui-line-height-{none…loose}` | |
|
|
234
|
+
| 字重 | `--fanui-font-weight-{light…extrabold}` | |
|
|
235
|
+
| 字距 | `--fanui-tracking-{tighter…widest}` | |
|
|
236
|
+
| 间距 | `--fanui-space-{0…24}` | 4px 基准 |
|
|
237
|
+
| 圆角 | `--fanui-radius-{none…full}` | |
|
|
238
|
+
| 阴影 | `--fanui-shadow-{none…2xl\|inner}` | |
|
|
239
|
+
| 层级 | `--fanui-z-{dropdown…toast}` | |
|
|
240
|
+
| 动效 | `--fanui-duration-{instant…slower}` / `--fanui-ease-{…}` | |
|
|
241
|
+
| 控件 | `--fanui-control-h`, `--fanui-control-px`, `--fanui-control-radius` | |
|
|
242
|
+
| 断点 | `--fanui-bp-{xs…xxl}` | 供 JS 读取,保证 CSS/JS 一致 |
|
|
243
|
+
|
|
244
|
+
### 主题切换
|
|
245
|
+
|
|
246
|
+
```html
|
|
247
|
+
<!-- 三条运行时轴,可任意组合 -->
|
|
248
|
+
<html data-fanui-theme="auto" data-fanui-accent="violet" data-fanui-glass="on">
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
```js
|
|
252
|
+
// 深浅模式(v1 兼容 API 保留)
|
|
253
|
+
FanUI.theme.set("dark");
|
|
254
|
+
FanUI.theme.toggle();
|
|
255
|
+
|
|
256
|
+
// v2:12 主题色 / 深浅 / 玻璃 三轴控制
|
|
257
|
+
FanUI.theme.setAccent("emerald"); // 12 选 1,全组件即时生效
|
|
258
|
+
FanUI.theme.setMode("dark"); // light / dark / auto
|
|
259
|
+
FanUI.theme.setGlass(false); // 玻璃总开关
|
|
260
|
+
FanUI.theme.setGlassIntensity(1.4); // 液态强度 0–2
|
|
261
|
+
FanUI.theme.setGlassPreset("lens"); // thin/regular/thick/ultra/lens
|
|
262
|
+
FanUI.theme.createAccent("#ff6b35"); // 任意品牌色 → 合规主题(自动对比度选阶)
|
|
263
|
+
|
|
264
|
+
document.addEventListener("fanui:accentchange", e => console.log(e.detail));
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
> 主题角色令牌 / 玻璃令牌 / 自动可达性算法等完整规范见 **[DESIGN-SYSTEM.md](./DESIGN-SYSTEM.md)**。
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 7. 组件清单
|
|
272
|
+
|
|
273
|
+
| 模块 | 主要类名 |
|
|
274
|
+
|---|---|
|
|
275
|
+
| 按钮 | `.fanui-btn` `--primary/success/warning/danger/info/accent/neutral/white` `--outline/ghost/text/link` `--xs…--xl` `--block/square/circle/pill` `--loading`;`.fanui-btn-group` |
|
|
276
|
+
| 表单 | `.fanui-form` `-item` `-label` `-control` `-feedback` `-help` `-actions` `-section`;`.fanui-form-item` `--error/--success/--warning`;`.fanui-form-label` `--required/--optional`;`.fanui-textarea` `--xs…--xl`;`.fanui-input-group` `.fanui-search` `.fanui-dropzone` `.fanui-file` |
|
|
277
|
+
| 选择 | `.fanui-select` `.fanui-checkbox` `.fanui-radio` `.fanui-switch` `.fanui-segmented` `.fanui-choice-group` |
|
|
278
|
+
| 卡片 | `.fanui-card` `__header/__body/__footer/__media/__title/__subtitle/__extra`;`--flat/elevated/glass/sunken/ghost/interactive/selected/horizontal/accent-bar`;`.fanui-panel` `.fanui-stat` |
|
|
279
|
+
| 表格 | `.fanui-table-wrap` `.fanui-table`;`--bordered/borderless/striped/hover/compact/roomy/fixed/align-*/sticky-head/sticky-col/{颜色}`;行状态 `.is-selected/.is-danger/.is-success/.is-warning` |
|
|
280
|
+
| 徽标 | `.fanui-badge` `--{颜色}` `--soft/outline/dot/pill/circle` `--xs…--lg`;`.fanui-tag` `.fanui-status` `.fanui-badge-sup` |
|
|
281
|
+
| 基础 | `.fanui-code`(行内代码 / 代码块) `.fanui-divider` |
|
|
282
|
+
| 警告框 | `.fanui-alert` `--{颜色}` `--solid/outline/sm/lg/banner/inline/flat`;`.fanui-toast` `.fanui-toast-region` |
|
|
283
|
+
| 导航 | `.fanui-navbar` `.fanui-nav` `.fanui-nav__item` `.fanui-sidebar` `.fanui-breadcrumb` `.fanui-menu`;`.fanui-anchor` `.fanui-anchor__link`(配合 `data-fanui-scrollspy` 目录高亮) |
|
|
284
|
+
| 选项卡 | `.fanui-tabs` `--line/card/pill/segmented/vertical`;`.fanui-accordion` `.fanui-collapse` |
|
|
285
|
+
| 浮层 | `.fanui-modal` `--sm/md/lg/xl/full/top/bottom`;`.fanui-drawer` `--start/end/top/bottom`;`.fanui-dropdown` `.fanui-tooltip` `.fanui-popover` |
|
|
286
|
+
| 反馈 | `.fanui-progress` `--{颜色}/striped/animated/indeterminate` `.fanui-progress-ring` `.fanui-spinner` `.fanui-loading` `.fanui-skeleton` `.fanui-empty` `.fanui-result`;`.fanui-loading-bar` `--indeterminate`(对应 `FanUI.loadingBar`) |
|
|
287
|
+
| 数据 | `.fanui-avatar` `--xs…2xl` `.fanui-avatar-group` `.fanui-list-group` `.fanui-list-item` `.fanui-descriptions` `.fanui-pagination` `.fanui-steps` `.fanui-timeline`;`.fanui-cascader` `.fanui-tree` `.fanui-transfer`(对应 `FanUI.cascader` / `FanUI.tree` / `FanUI.transfer`) |
|
|
288
|
+
| 布局 | `.fanui-container` `.fanui-row` `.fanui-col` `.fanui-bento`;`.fanui-stack` `fanui-stack-space` `--sm/--lg`;`.fanui-cluster` `--center/--between/--end/--tight/--loose` |
|
|
289
|
+
| 玻璃 | `.fanui-glass` `--thin/regular/thick/ultra/lens` `--card/bar/panel/square/sharp/reactive` `--flow/--static/--lens`;组件玻璃形态 `.fanui-{card,navbar,modal,drawer,dropdown,toast,alert,btn,table}--glass` |
|
|
290
|
+
| 进阶表单 | `.fanui-slider`(+`--sm/--lg`/双滑块/气泡) `.fanui-rate` `.fanui-upload` `.fanui-tag-input` `.fanui-stepper` `.fanui-pin` `.fanui-swatch` `.fanui-combobox`;`.fanui-datepanel` `.fanui-timepanel` `.fanui-colorpanel`(对应 `FanUI.datePicker` / `FanUI.timePicker` / `FanUI.colorPicker`) |
|
|
291
|
+
| 交互创新 | `.fanui-command`(⌘K) `.fanui-dock`(`:has()` 邻域放大) `.fanui-carousel` `.fanui-fab` `.fanui-scroll-progress` `.fanui-spotlight` `.fanui-cursor-glow` `.fanui-studio` `.fanui-sheet` `.fanui-bottom-nav` |
|
|
292
|
+
| 营销场景 | `.fanui-announcement` `.fanui-hero` `.fanui-section-head` `.fanui-feature` `.fanui-bento` `.fanui-flow` `.fanui-marquee` `.fanui-stat-band` `.fanui-pricing` `.fanui-testimonial` `.fanui-cta` `.fanui-faq` `.fanui-footer`;`.fanui-logo-cloud`(客户 Logo 墙) |
|
|
293
|
+
| 博客场景 | `.fanui-read-meta` `.fanui-post-card` `.fanui-article` `.fanui-toc` `.fanui-author` `.fanui-share` `.fanui-comment` `.fanui-newsletter` `.fanui-related` `.fanui-tag-cloud` |
|
|
294
|
+
| B 端场景 | `.fanui-kpi` `.fanui-bars` `.fanui-donut` `.fanui-legend` `.fanui-usage` `.fanui-kanban` `.fanui-activity` `.fanui-notify` `.fanui-filter-bar` |
|
|
295
|
+
| 能力补齐(v2.1) | `.fanui-virtual-list`(`__source/__inner/__item/__empty`,JS 接管后加 `.is-virtualized`);`.fanui-lightbox` `.fanui-lightbox-trigger`(`__stage/__img/__nav/__toolbar/__thumbstrip/__counter/__caption/__backdrop`);`.fanui-watermark` `__host`;`.fanui-tour`(`__mask/__spotlight/__popover/__arrow/__dots/__actions`);`.fanui-splitter` `--vertical`(`__pane/__bar/__bar-handle`,拖拽中 `.is-resizing`);`[data-fanui-affix]`(JS 生成 `.fanui-affix__placeholder/__inner`);`.fanui-backtop`(`__icon/__ring`,显示态 `.is-visible`)。对应 `FanUI.virtualList` / `FanUI.lightbox` / `FanUI.watermark` / `FanUI.tour` / `FanUI.splitter` / `FanUI.affix` / `FanUI.backTop`(注意是 `backTop`);均支持零 JS 自动初始化属性 `data-fanui-virtual-list` `data-fanui-lightbox` `data-fanui-watermark` `data-fanui-tour` `data-fanui-splitter` `data-fanui-affix` `data-fanui-backtop`,配 `-src/-group/-caption/-thumb`、`-sub/-gap/-rotate/-opacity/-image`、`-direction`、`-offset/-target`、`-auto/-container` 修饰 |
|
|
296
|
+
| 纹理工具 | `.fanui-bg-aurora/mesh/dots/grid-fade/conic/noise` `.fanui-glow` `.fanui-text-brand/text-aurora` `.fanui-shimmer` `.fanui-border-gradient` `.fanui-mask-*` `.fanui-ripple-*` |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 8. 构建与质量验证
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
npm install # 安装 dart-sass(唯一开发依赖)
|
|
304
|
+
npm run build # 产出 dist/fanui.css + fanui.min.css + fanui.js
|
|
305
|
+
npm run watch # 监听编译
|
|
306
|
+
npm run serve # 本地起服务预览 demo/index.html
|
|
307
|
+
|
|
308
|
+
node scripts/audit-theme.cjs # 对比度审计:12 主题 × 明暗,60/60 项 ≥4.5:1 → theme-audit.md
|
|
309
|
+
node scripts/verify-demo.cjs # 真实浏览器回归:0 console error · 48 组合遍历 · 交互回归 · 14 张截图
|
|
310
|
+
node scripts/verify-examples.cjs # 示例页回归(examples/01、04 的结构断言 + 截图)
|
|
311
|
+
node scripts/probe-entries.cjs # 打包入口验证:ESM(浏览器原生模块)/ CJS(Node 安全空导出)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
> **版本要求**:`sass >= 1.79.0`(项目使用 `color.channel()` 等现代色彩 API,编译零弃用告警)。
|
|
315
|
+
> **浏览器验证**:需本机安装 Chrome;`verify-demo.cjs` 自动定位托管工作区的 `playwright-core`,产物输出到 `demo/shots/`。
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## 9. 设计约定
|
|
320
|
+
|
|
321
|
+
- **三条正交运行时轴**:主题色(`data-fanui-accent`)· 深浅模式(`data-fanui-theme`)· 玻璃(`data-fanui-glass`),相互独立、运行时切换、零重编译。
|
|
322
|
+
- **组件只消费角色令牌**:任何组件不得写死主题色值,保证换主题全组件一致生效。
|
|
323
|
+
- **自动可达性**:实心色由色阶中自动挑选对比度达标(≥4.5:1)的一阶,任意品牌色接入即合规。
|
|
324
|
+
- **移动优先**:所有断点媒体查询均为 `min-width`,基础样式面向最窄屏。
|
|
325
|
+
- **零 `!important` 滥用**:仅在工具类与显示控制等必要处使用。
|
|
326
|
+
- **可访问性**:全部交互控件保留原生语义(`<button>`/`<input>`/`<label>`),提供 `.fanui-visually-hidden`、`.fanui-skip-link`、`:focus-visible` 焦点环(随主题色)、`forced-colors` 高对比模式与 `prefers-reduced-motion` / `prefers-reduced-transparency` 自动降级。
|
|
327
|
+
- **动效克制**:统一 `--fanui-duration-*` / `--fanui-ease-*`。
|
|
328
|
+
- **中国市场约定**:`.fanui-stat__trend--up` 为红色(涨),`--down` 为绿色(跌)。
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## 授权(License)
|
|
333
|
+
|
|
334
|
+
fanUI 采用 **AGPL-3.0-or-later 与商业许可的双许可模式** —— 同一个软件,两条授权路径,按使用场景选一条:
|
|
335
|
+
|
|
336
|
+
| 许可证 | 适用场景 | 费用 | 源码义务 |
|
|
337
|
+
| --- | --- | --- | --- |
|
|
338
|
+
| **[AGPL-3.0-or-later](./LICENSE)** | 个人学习、课程作业、技术调研;AGPL 兼容的开源项目;不对外提供网络服务的内部系统 | 免费 | 分发**或对外提供服务**时须按 AGPL 开源(含你对 fanUI 的修改) |
|
|
339
|
+
| **商业许可** | 闭源商业产品、闭源 SaaS、OEM / 白标、需要书面授权凭证的企业采购 | 按授权类型付费 | 无需开源,可闭源使用 |
|
|
340
|
+
|
|
341
|
+
逐场景的选择指引、商业授权获取方式与贡献者条款见 **[COMMERCIAL-LICENSE.md](./COMMERCIAL-LICENSE.md)**。
|
|
342
|
+
`package.json` 中对应声明为 `"license": "AGPL-3.0-or-later"`(标准 SPDX 标识,企业合规扫描器可识别)。
|
|
343
|
+
|
|
344
|
+
> **AGPL 与 GPL 的关键差异在「第 13 条 远程网络交互」**:即使你**不分发**代码,
|
|
345
|
+
> 只要把 fanUI 用在**对外提供服务的网络应用**里(网站 / SaaS),也必须向这些用户提供完整对应源码。
|
|
346
|
+
> 这正是「闭源商用需要购买商业许可」的根源 —— 购买商业许可后,该范围内的 AGPL 开源义务被商业条款替代。
|
|
347
|
+
>
|
|
348
|
+
> 授权询价见官网「定价」分区的联系渠道(微信 / QQ);企业采购可开具发票。
|