diff --git a/.trae/specs/fused-desktop-library-redesign/spec.md b/.trae/specs/fused-desktop-library-redesign/spec.md index 161211c..4e8e4c3 100644 --- a/.trae/specs/fused-desktop-library-redesign/spec.md +++ b/.trae/specs/fused-desktop-library-redesign/spec.md @@ -1,100 +1,166 @@ # 融合桌面组件库窗口重设计规格 ## Why + 当前融合桌面组件库窗口(FusedDesktopComponentLibraryWindow)的UI设计较为基础,与Windows 11小组件编辑面板相比,缺乏现代化的交互体验和视觉层次。用户需要一个更直观、更美观的界面来浏览和添加组件到系统桌面(负一屏)。 参考Windows 11小组件编辑面板的设计特点: -- 左侧分类列表,右侧选中组件的详细预览 -- 大型组件预览区域,让用户清楚看到组件效果 -- 底部明显的"添加"操作按钮 -- 简洁的关闭按钮(X)在右上角 -- 深色主题配合毛玻璃效果 + +* 左侧分类列表,右侧选中组件的详细预览 + +* 大型组件预览区域,让用户清楚看到组件效果 + +* 底部明显的"添加"操作按钮 + +* 简洁的关闭按钮(X)在右上角 + +* 深色主题配合毛玻璃效果 ## What Changes -- **重新设计窗口布局**:从左右分栏(分类列表+组件网格)改为左侧面板+右侧预览区的布局 -- **添加组件详情预览区**:选中组件后右侧显示大尺寸预览和组件信息 -- **优化关闭按钮**:使用标准的X图标按钮,不使用圆形样式 -- **添加底部操作栏**:包含"添加到桌面"主操作按钮和"查找更多组件"链接 -- **复用阑山桌面组件库分类**:使用相同的分类ID、图标和本地化文本 -- **移除搜索功能**:参考Windows 11设计,暂不提供搜索 + +* **重新设计窗口布局**:从左右分栏(分类列表+组件网格)改为左侧面板+右侧预览区的布局 + +* **添加组件详情预览区**:选中组件后右侧显示大尺寸预览和组件信息 + +* **优化关闭按钮**:使用标准的X图标按钮,不使用圆形样式 + +* **添加底部操作栏**:包含"添加到桌面"主操作按钮和"查找更多组件"链接 + +* **复用阑山桌面组件库分类**:使用相同的分类ID、图标和本地化文本 + +* **移除搜索功能**:参考Windows 11设计,暂不提供搜索 ## Impact -- 受影响文件: - - `LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml` - - `LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml.cs` - - `LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml` - - `LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml.cs` - - `LanMountainDesktop/ViewModels/ComponentLibraryWindowViewModel.cs`(可能需要添加新属性) + +* 受影响文件: + + * `LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml` + + * `LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml.cs` + + * `LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml` + + * `LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml.cs` + + * `LanMountainDesktop/ViewModels/ComponentLibraryWindowViewModel.cs`(可能需要添加新属性) ## ADDED Requirements ### Requirement: 窗口布局重设计 + 系统应提供一个类似于Windows 11小组件编辑面板的组件库窗口。 #### Scenario: 窗口整体结构 -- **GIVEN** 用户从托盘菜单打开融合桌面组件库 -- **WHEN** 窗口显示时 -- **THEN** 窗口应呈现: - - 顶部标题栏:左侧显示"添加小组件"标题,右侧有关闭按钮(X) - - 左侧面板:分类列表(复用阑山桌面组件库的分类和图标) - - 右侧主区域:选中组件的大尺寸预览 + 组件信息 + 添加按钮 - - 底部:"查找更多组件"链接 + +* **GIVEN** 用户从托盘菜单打开融合桌面组件库 + +* **WHEN** 窗口显示时 + +* **THEN** 窗口应呈现: + + * 顶部标题栏:左侧显示"添加小组件"标题,右侧有关闭按钮(X) + + * 左侧面板:分类列表(复用阑山桌面组件库的分类和图标) + + * 右侧主区域:选中组件的大尺寸预览 + 组件信息 + 添加按钮 + + * 底部:"查找更多组件"链接 #### Scenario: 分类列表交互 -- **GIVEN** 左侧显示组件分类列表 -- **WHEN** 用户点击某个分类 -- **THEN** 右侧应显示该分类下的第一个组件的预览 -- **AND** 分类项应有选中状态视觉反馈 -- **AND** 分类图标和名称应与阑山桌面组件库保持一致 + +* **GIVEN** 左侧显示组件分类列表 + +* **WHEN** 用户点击某个分类 + +* **THEN** 右侧应显示该分类下的第一个组件的预览 + +* **AND** 分类项应有选中状态视觉反馈 + +* **AND** 分类图标和名称应与阑山桌面组件库保持一致 #### Scenario: 组件预览区 -- **GIVEN** 用户选中一个组件 -- **WHEN** 预览区显示时 -- **THEN** 应显示: - - 组件标题(大字号) - - 大尺寸组件预览图(接近实际尺寸) - - 组件描述/功能说明 - - 底部"添加到桌面"按钮 + +* **GIVEN** 用户选中一个组件 + +* **WHEN** 预览区显示时 + +* **THEN** 应显示: + + * 组件标题(大字号) + + * 大尺寸组件预览图(接近实际尺寸) + + * 组件描述/功能说明 + + * 底部"添加到桌面"按钮 #### Scenario: 添加组件操作 -- **GIVEN** 用户查看组件预览 -- **WHEN** 用户点击"添加到桌面"按钮 -- **THEN** 组件应被添加到系统桌面(负一屏)中央 -- **AND** 窗口应关闭 + +* **GIVEN** 用户查看组件预览 + +* **WHEN** 用户点击"添加到桌面"按钮 + +* **THEN** 组件应被添加到系统桌面(负一屏)中央 + +* **AND** 窗口应关闭 #### Scenario: 关闭按钮样式 -- **GIVEN** 窗口标题栏有关闭按钮 -- **THEN** 关闭按钮应使用标准的X图标 -- **AND** 不使用圆形背景或特殊样式 -- **AND** 使用 `DesignCornerRadiusSm` 动态资源 + +* **GIVEN** 窗口标题栏有关闭按钮 + +* **THEN** 关闭按钮应使用标准的X图标 + +* **AND** 不使用圆形背景或特殊样式 + +* **AND** 使用 `DesignCornerRadiusSm` 动态资源 #### Scenario: 查找更多组件链接 -- **GIVEN** 窗口底部显示"查找更多组件"链接 -- **WHEN** 用户点击该链接 -- **THEN** 应打开设置窗口的插件目录页面(后续将改为插件市场) + +* **GIVEN** 窗口底部显示"查找更多组件"链接 + +* **WHEN** 用户点击该链接 + +* **THEN** 应打开设置窗口的插件目录页面(后续将改为插件市场) ## MODIFIED Requirements ### Requirement: 组件列表展示 + 原实现使用网格展示所有组件,新实现改为: -- 左侧列表仅显示分类(复用阑山桌面组件库的分类ID和图标映射) -- 右侧预览区一次只显示一个组件的详细信息 -- ~~移除搜索功能~~(根据Windows 11设计,暂不提供搜索) + +* 左侧列表仅显示分类(复用阑山桌面组件库的分类ID和图标映射) + +* 右侧预览区一次只显示一个组件的详细信息 + +* ~~移除搜索功能~~(根据Windows 11设计,暂不提供搜索) ### Requirement: 关闭按钮圆角规范 + 原实现关闭按钮使用硬编码 `CornerRadius="18"`,应改为使用动态资源 `DesignCornerRadiusSm`。 ### Requirement: 分类图标复用 + 分类图标映射应与阑山桌面组件库保持一致: -- Clock -> Symbol.Clock -- Date -> Symbol.CalendarDate -- Weather -> Symbol.WeatherSunny -- Board -> Symbol.Edit -- Media -> Symbol.Play -- Info -> Symbol.Info -- Calculator -> Symbol.Calculator -- Study -> Symbol.Hourglass -- 其他 -> Symbol.Apps + +* Clock -> Symbol.Clock + +* Date -> Symbol.CalendarDate + +* Weather -> Symbol.WeatherSunny + +* Board -> Symbol.Edit + +* Media -> Symbol.Play + +* Info -> Symbol.Info + +* Calculator -> Symbol.Calculator + +* Study -> Symbol.Hourglass + +* 其他 -> Symbol.Apps ## REMOVED Requirements -- ~~搜索功能~~:根据Windows 11小组件面板设计,暂不提供搜索功能 + +* ~~搜索功能~~:根据Windows 11小组件面板设计,暂不提供搜索功能 + diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ad52ab..029742a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,5 @@ # 更新日志 / Changelog -所有重要的更改都将记录在此文件中。 - -格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), -并且本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。 - ---- - -## [Unreleased] - -### 新增 (Added) -- 待发布的新功能 - -### 变更 (Changed) -- 待发布的变更 - -### 修复 (Fixed) -- 待发布的修复 - -### 移除 (Removed) -- 待发布的移除项 - ---- ## [0.8.3.2] - 2026-04-09 @@ -70,6 +48,28 @@ --- +所有重要的更改都将记录在此文件中。 + +格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), +并且本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。 + +--- + +## [格式示例] + +### 新增 (Added) +- 待发布的新功能 + +### 变更 (Changed) +- 待发布的变更 + +### 修复 (Fixed) +- 待发布的修复 + +### 移除 (Removed) +- 待发布的移除项 + +--- ## 版本说明 ### 版本号规则 diff --git a/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml b/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml index 6e5f109..1593a58 100644 --- a/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml +++ b/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml @@ -34,11 +34,13 @@ + FontWeight="SemiBold" + TextTrimming="CharacterEllipsis" /> + FontWeight="SemiBold" + TextTrimming="CharacterEllipsis" /> diff --git a/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs b/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs index fe79931..424240d 100644 --- a/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs +++ b/LanMountainDesktop/Views/Components/ClassScheduleWidget.axaml.cs @@ -928,7 +928,28 @@ public partial class ClassScheduleWidget : UserControl, IDesktopComponentWidget, MetaStack.Spacing = Math.Clamp(6 * scale, 3, 10); CourseListPanel.Spacing = Math.Clamp(6 * scale, 3, 10); - var dateFont = Math.Clamp(66 * scale, 26, 82); + var dateFontByScale = Math.Clamp(66 * scale, 26, 82); + var weekdayFontByScale = Math.Clamp(34 * scale, 13, 32); + var classCountFontByScale = Math.Clamp(40 * scale, 14, 36); + + // 宽度感知:当头部内容总需求超过可用宽度时,按比例缩小日期字体 + var availableWidth = Math.Max(1, Bounds.Width - rootPadding.Left - rootPadding.Right); + var dateGroupEstimatedWidth = dateFontByScale * 0.6 * 3 + DateGroup.Spacing * 2; + var metaStackEstimatedWidth = classCountFontByScale * 0.6 * 4 + MetaStack.Spacing; + var headerColumnSpacing = Math.Clamp(10 * scale, 4, 16); + var totalHeaderNeed = dateGroupEstimatedWidth + headerColumnSpacing + metaStackEstimatedWidth; + + var dateFont = dateFontByScale; + if (totalHeaderNeed > availableWidth) + { + var shrinkRatio = availableWidth / totalHeaderNeed; + dateFont = Math.Max(20, dateFontByScale * shrinkRatio); + } + + // 为 HeaderGrid 左列设置最小宽度,防止被压缩至零 + var minDateColumnWidth = dateFont * 0.6 * 3 + DateGroup.Spacing * 2; + HeaderGrid.ColumnDefinitions[0].MinWidth = minDateColumnWidth; + MonthTextBlock.FontSize = dateFont; DayTextBlock.FontSize = dateFont; SlashTextBlock.FontSize = dateFont; @@ -940,8 +961,8 @@ public partial class ClassScheduleWidget : UserControl, IDesktopComponentWidget, ClassCountTextBlock.Foreground = CreateBrush(_isNightVisual ? "#8D95A4" : "#738095"); StatusTextBlock.Foreground = CreateBrush(_isNightVisual ? "#9AA2B1" : "#4B5565"); - WeekdayTextBlock.FontSize = Math.Clamp(34 * scale, 13, 32); - ClassCountTextBlock.FontSize = Math.Clamp(40 * scale, 14, 36); + WeekdayTextBlock.FontSize = weekdayFontByScale; + ClassCountTextBlock.FontSize = classCountFontByScale; StatusTextBlock.FontSize = Math.Clamp(30 * scale, 12, 30); WeekdayTextBlock.FontWeight = ToVariableWeight(Lerp(560, 700, Math.Clamp((scale - 0.60) / 1.2, 0, 1))); diff --git a/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs b/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs index 6a4a5da..77139ac 100644 --- a/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs +++ b/LanMountainDesktop/Views/Components/CnrDailyNewsWidget.axaml.cs @@ -704,6 +704,24 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget, ExtraNewsItemsPanel.Spacing = Math.Clamp(6 * scale, 3, 10); ApplyNightModeVisual(); + + var headerHeight = refreshHeight; + var newsItemHeight = Math.Max(imageHeight, mainNewsMinHeight); + + var requiredHeight = verticalPadding * 2 + + headerHeight + + rowSpacing + + newsItemHeight + + rowSpacing + + newsItemHeight; + + if (_extraNewsRows.Count > 0) + { + var extraSpacing = ExtraNewsItemsPanel.Spacing * (_extraNewsRows.Count - 1); + requiredHeight += rowSpacing + extraSpacing + _extraNewsRows.Count * newsItemHeight; + } + + this.MinHeight = requiredHeight; } private void UpdateRefreshButtonState() @@ -842,6 +860,11 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget, oldBitmap?.Dispose(); _newsBitmaps[index] = bitmap; imageControl.Source = bitmap; + + if (bitmap != null) + { + InvalidateMeasure(); + } } private void DisposeNewsBitmaps() diff --git a/design.md b/design.md new file mode 100644 index 0000000..1df479e --- /dev/null +++ b/design.md @@ -0,0 +1,683 @@ +# UI Design System Guide (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 + + + + + + + + + +``` + +#### 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 强制规则