# UI Design System Guide (design.md)
> Settings window shell-specific rules live in `docs/ai/SETTINGS_WINDOW_DESIGN.md`.
> **目标**: 让 AI 正确使用 Fluent Avalonia / Fluent Icons / Material Avalonia,避免窗口套窗口、容器套容器
>
> **最后更新**: 2026-04-11
---
## 一句话总结
**主界面用 Fluent + FluentIcon,编辑器用 Material + MaterialIcon,永远不要混用,保持扁平结构。**
---
## 1. 技术栈与职责
### 1.1 库清单
| 库 | 包名 | 什么时候用 |
|---|------|----------|
| **FluentAvaloniaUI** | `FluentAvaloniaUI` | 主界面、设置页、导航 |
| **FluentIcons.Avalonia.Fluent** | `FluentIcons.Avalonia.Fluent` | 主界面图标(**首选**)|
| **FluentIcons.Avalonia** | `FluentIcons.Avalonia` | 旧图标兼容(SymbolIcon)|
| **Material.Icons.Avalonia** | `Material.Icons.Avalonia` | 编辑器图标(**仅限 ComponentEditorWindow**)|
| **Material.Avalonia** | `Material.Avalonia` | MD3 主题(**仅限 ComponentEditorWindow**)|
### 1.2 初始化顺序(App.axaml)
```xml
```
---
## 2. 命名空间速查表
**复制粘贴用:**
```xml
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:fi="using:FluentIcons.Avalonia.Fluent"
xmlns:local="using:LanMountainDesktop.Controls"
xmlns:comp="using:LanMountainDesktop.Views.Components"
```
---
## 3. 图标系统
### 3.1 选择决策树
```
你在写什么?
├─ 设置页面 / 主界面 / 桌面组件?
│ └─ 用 FluentIcon(fi:FluentIcon)
│ ├─ 需要 Filled/Regular 切换?→ IconVariant="Filled" 或 "Regular"
│ └─ 简单静态图标?→ 也用 FluentIcon,不用 SymbolIcon
│
├─ ComponentEditorWindow 及其子页面?
│ └─ 用 MaterialIcon(mi:MaterialIcon)
│
└─ 其他情况?
└─ 默认 FluentIcon
```
### 3.2 FluentIcon 使用方法
```xml
IconVariant="Filled"
Classes="icon-m" />
```
**常用图标名称:**
- 导航类:`Home`, `Settings`, `Navigation`, `ArrowLeft`, `ChevronRight`, `Dismiss`
- 操作类:`Add`, `Delete`, `Edit`, `Save`, `Refresh`, `Sync`, `ArrowSync`
- 状态类:`Info`, `Warning`, `ErrorBadge`, `CheckmarkCircle`
- 外观类:`ThemeLightDark`, `ColorBackground`, `Appearance`
### 3.3 MaterialIcon 使用方法(仅限编辑器)
```xml
Width="24"
Height="24"
Foreground="{DynamicResource EditorPrimaryBrush}" />
```
**常用 Kind 值:**
- 操作:`Close`, `Check`, `Pencil`, `Delete`, `Settings`, `Plus`
- 导航:`ArrowLeft`, `ArrowRight`, `Home`, `Menu`
- 系统:`Power`, `Lock`, `ExitToApp`, `Refresh`, `WeatherNight`
### 3.4 ❌ 禁止事项
```xml
```
---
## 4. 容器嵌套规范(核心!)
### 4.1 最大深度限制
| 场景 | 最大层数 | 从哪里开始数 |
|-----|---------|------------|
| 普通页面 | **≤ 4 层** | Window/UserControl → ... → 叶子节点 |
| Popup/Dialog | **≤ 3 层** | Border → Content |
| 列表项/DataTemplate | **≤ 3 层** | Root → ... → 元素 |
| MainWindow 桌面布局 | **≤ 6 层** | 特殊允许(多层叠加需求)|
### 4.2 如何数层级?
从根元素到目标元素经过的容器标签数:
```xml
```
### 4.3 推荐的标准结构
#### 结构 A:标准设置页面(3-4 层)
```xml
```
#### 结构 B:卡片/面板组件(3 层)
```xml
```
#### 结构 C:列表项(2-3 层)
```xml
```
### 4.4 ❌ 反模式:过度嵌套
```xml
```
### 4.5 何时可以超过限制?
只有这 3 种情况:
1. **MainWindow 桌面布局**(壁纸层 + 组件层 + 拖拽层 + 任务栏)
2. **需要独立动画层**(Transform/Opacity 动画需要单独容器)
3. **复杂 Popup 内部**
**必须加注释说明原因:**
```xml
...
```
---
## 5. 窗口 vs UserControl vs Border
### 5.1 什么时候用什么?
| 需求 | 用什么 | 示例 |
|-----|-------|------|
| 独立窗口(有标题栏、可拖动、任务栏可见)| **Window** | SettingsWindow, ComponentEditorWindow |
| 可复用的 UI 组件块 | **UserControl** | SettingsOptionCard, ClockWidget |
| 视觉上的卡片/面板/容器 | **Border** | 设置分区卡片、弹出面板 |
### 5.2 ❌ 禁止:窗口套窗口
```csharp
// ❌ 错误:在 XAML 中实例化另一个 Window
//
// ✅ 正确:通过代码显示独立窗口
var settings = new SettingsWindow { Owner = this };
settings.Show();
```
### 5.3 ❌ 禁止:把 Window 当 UserControl 用
```xml
Width="620"
Height="320"
CornerRadius="36">
```
**如果它不是真正的操作系统窗口,就用 Border 或 UserControl。**
---
## 6. 颜色与资源使用规范
### 6.1 必须使用 DynamicResource
```xml
```
### 6.2 常用资源键速查
| 资源键 | 用途 | 示例场景 |
|--------|------|---------|
| `AdaptiveTextPrimaryBrush` | 主要文本 | 标题、正文 |
| `AdaptiveTextSecondaryBrush` | 次要文本 | 描述文字、提示 |
| `AdaptiveSurfaceRaisedBrush` | 抬高表面 | 卡片背景、面板 |
| `AdaptiveSurfaceOverlayBrush` | 覆盖层 | 遮罩、弹窗背景 |
| `AccentBrush` | 强调色 | 主按钮、选中态 |
| `AppFontFamily` | 应用字体 | 全局字体设置 |
### 6.3 圆角 Token(强制!)
```xml
```
---
## 7. FluentAvaloniaUI 控件用法
### 7.1 NavigationView(设置页导航)
```xml
OpenPaneLength="283"
IsSettingsVisible="False"
IsBackButtonVisible="False"
SelectionChanged="OnNavChanged">
```
### 7.2 Frame(页面导航容器)
```xml
```
```csharp
// C# 代码中导航
ContentFrame.Navigate(typeof(SettingsHomePage));
// 或绑定
ContentFrame.SourcePageType = typeof(SettingsHomePage);
```
### 7.3 InfoBar(内联通知条)
```xml
IsOpen="True"
ActionButtonText="立即更新"
ActionButtonClick="OnUpdateClick"
CloseButtonClick="OnDismissClick" />
```
### 7.4 ContentDialog(模态对话框)
```csharp
var dialog = new ContentDialog
{
Title = "确认删除",
Content = "确定要删除吗?此操作不可撤销。",
PrimaryButtonText = "删除",
CloseButtonText = "取消",
DefaultButton = ContentDialogButton.Primary
};
var result = await dialog.ShowAsync(this);
if (result == ContentDialogResult.Primary)
{
}
```
---
## 8. Material.Avalonia 使用规范(严格限制!)
### 8.1 ⚠️ 只能在这里用
**✅ 允许:**
- `ComponentEditorWindow.axaml`
- ComponentEditorWindow 的子编辑页面
**❌ 禁止:**
- MainWindow
- SettingsWindow
- NotificationWindow
- 任何桌面组件(Widget)
- 任何其他地方
### 8.2 如何在 ComponentEditorWindow 中启用
```xml
```
### 8.3 MD3 组件示例
#### FAB 按钮(浮动操作按钮)
```xml
```
#### Top App Bar(顶栏)
```xml
```
---
## 9. 实战代码模板
### 模板 1:新建设置页面
文件位置:`Views/Settings/YourPageName.axaml`
```xml
```
**嵌套检查:** ScrollViewer(1) > StackPanel(2) > Border(3) > StackPanel(4) > Items(5) ✅ (因为有 ScrollViewer 容器,5 层可接受)
### 模板 2:新建桌面小组件
文件位置:`Views/Components/YourWidget.axaml`
```xml
```
**嵌套检查:** Border(1) > Grid(2) > Elements(3) ✅ 完美!
### 模板 3:新建独立窗口
```xml
```
**嵌套检查:** Grid(1) > Border(2) > Grid(3) > Elements(4) ✅
---
## 10. AI 编码检查清单
### 写代码前问自己
- [ ] 这个文件是设置页/主界面?→ 用 Fluent + FluentIcon
- [ ] 这个文件是 ComponentEditorWindow?→ 用 Material + MaterialIcon
- [ ] 我用了正确的命名空间吗?(见第 2 节速查表)
- [ ] 图标用了 Classes="icon-s/m/l" 而非硬编码 FontSize 吗?
### 写完代码后检查
- [ ] 数一下最大嵌套深度(见第 4.2 节)
- [ ] 有没有硬编码颜色值?(应该都用 DynamicResource)
- [ ] 有没有硬编码 CornerRadius?(应该用 DesignCornerRadiusXxx)
- [ ] 有没有在同一区域混用 FluentIcon 和 MaterialIcon?
- [ ] 是不是不小心写了 `` 在另一个 Window 里?
- [ ] 是不是连续写了 Border > Grid > Border > Grid 可以合并?
### 如果审查别人代码
- [ ] 发现窗口套窗口了吗?
- [ ] 发现超过 4 层的无意义嵌套了吗?(没有注释说明原因的话)
- [ ] 发现 Fluent 和 Material 控件混在同一区域了吗?
- [ ] 发现应该用 DynamicResource 的地方硬编码了吗?
---
## 附录:常见错误快速修复
| 错误现象 | 问题原因 | 修复方法 |
|---------|---------|---------|
| 图标不显示或大小不对 | 用了错误的命名空间或硬编码尺寸 | 改用 `fi:FluentIcon` + `Classes="icon-m"` |
| 圆角在设置里改了但没生效 | 硬编码了 CornerRadius | 改用 `{DynamicResource DesignCornerRadiusComponent}` |
| 深色模式下颜色刺眼 | 硬编码了颜色值 | 改用 `{DynamicResource AdaptiveTextPrimaryBrush}` 等 |
| 设置页风格和其他窗口不一致 | 混用了 Material 控件 | 统一用 FluentAvaloniaUI 控件 |
| 性能差/渲染慢 | 嵌套太深(>6 层)| 扁平化结构,合并多余容器 |
| 弹窗显示位置/大小异常 | 把 Window 当成 UserControl 嵌套了 | 改为代码中 `.Show()` 显示 |
---
**相关文档:**
- [VISUAL_SPEC.md](./VISUAL_SPEC.md) - 视觉规范总纲
- [CORNER_RADIUS_SPEC.md](./CORNER_RADIUS_SPEC.md) - 圆角详细规范
- AGENTS.md - AI 强制规则