- 桌面应用
- 开发工具
【免费下载链接】MooTool
Handy tool set for developers
本文围绕 next-flutter/docs/adr/007-ui.md 这份已采纳的架构决策记录展开,深入讲解 MooTool Next Flutter 桌面端在界面布局、主题系统、导航模式与键盘快捷键上的具体设计约定,并结合仓库内 Dart 源码、设置页与单元测试,说明每一项约定在代码中的落地方式。读完本文,你将掌握 MooTool 这套"沉浸式工具区 + 主题 Token 换肤 + 快捷键双平台映射"的界面架构如何工作,以及哪些参数在设置界面中真实可调、哪些行为仍是规划中的状态。
一、ADR 007 决策概览
ADR(Architecture Decision Record)007 记录的是 MooTool Next Flutter 产品在 UI 层面的一组关键设计决策,状态为「已采纳」,日期为 2026-09-08。它一共锁定了五类约定:
- 沉浸式工具区:工具页面不使用大标题、面包屑或整页卡片,界面直接呈现工具内容本身。
- Token 主题体系:以
modern风格为主指南色板,并为产品补齐quiet、hero、smartisan、miui-v5、claude五套独立 workspace/sidebar/accent token;选择风格会真实改变表面色与强调色,而不是一个"假开关"。 - 强调色预设:6 个预设 id(
yellow/coral/blue/green/red/purple)会进入ColorScheme,同时旧配置值#4f83cc仍能正常解析。 - 导航模式:默认
classic;grouped显示组标题;card尚无独立视觉。 - 快捷键:⌘/Ctrl+K 搜索、⌘/Ctrl+, 设置、⌘/Ctrl+F 查找、⌘/Ctrl+S 保存、⌘/Ctrl+Enter 格式化;macOS 上显示 Command 符号,同时通过
LogicalKeyboardKey监听 Control。 - 分离窗口:在 P2 阶段是"同一 engine 内的状态机",并非原生独立 NSWindow。
下面逐条对应源码展开。
二、沉浸式工具区:没有标题栏和卡片壳的工具页
ADR 的第一条约定是工具区不再承载"大标题 / 面包屑 / 整页卡片"这类装饰性容器。这一点从工作台布局上可以直接印证:在 next-flutter/lib/features/workbench/workbench.dart 中,Workbench的正文区由侧边栏_sidebar(tokens)与工作区_workspace(tokens)组成,工作区根据当前工具 id 直接分发到对应的工具页面(见该文件的_workspace方法,如'json' => JsonToolPage(...)、'http' => HttpToolPage(...)、'pdf' => PdfToolPage(...)),工具页外层没有任何统一的标题条或面包屑组件。
各工具页本身也延续了这种"直接干活"的风格。以 JSON 工具为例,next-flutter/lib/features/json/json_tool.dart 的页面结构是「工具栏 → 查找栏(按需展开)→ 分栏(文档库 / 编辑器 / 检视器)」,工具栏上只有与任务直接相关的操作按钮,不存在页面级大标题。从代码结构可以推断,沉浸式布局的收益是让工具内容占满可用区域,并让快捷键与右键操作成为主要交互入口。
三、主题 Token 体系:从枚举到六套真实色板
ADR 要求主题体系具备"真实换肤"能力,而不是只换一个开关的外观。仓库中的实现分为三层:枚举定义 → Token 生成 → 主题构建。
3.1 风格枚举与配置持久化
界面风格在 next-flutter/lib/app/settings.dart 中定义为枚举:
enum InterfaceStyle { modern, quiet, hero, smartisan, miuiV5, claude }该枚举通过AppSettings.interfaceStyle字段持久化到 JSON(settings.interfaceStyle.name),默认值是modern。也就是说,风格选择是写入设置文件的真实配置,重启后仍然生效。
3.2 Token 生成器:六套独立色板
核心实现在 next-flutter/lib/design/theme.dart:
MooTokens extends ThemeExtension<MooTokens>定义了一组语义化颜色字段:workspace、surface、sidebar、toolbar、border、textPrimary、textSecondary、accent、onAccent、focus,并给出light/dark两套内置常量。tokensFor(InterfaceStyle style, Brightness brightness)通过switch为每种风格各自返回一套完整的明/暗 token。例如:quiet采用接近灰阶的中性色,accent 也是低饱和的灰色(#5C5C56/ 暗色下#8F8F8F);hero使用深蓝主视觉,accent 为#1F5FBF(暗色#5B8DEF);smartisan走暖棕色调,accent 为#C45C26(暗色#E08A5A);miuiV5是明亮蓝,accent 为#0D84FF(暗色#4DA3FF);claude是米白暖色系,accent 为#D97757(暗色#E09A7A)。
tokensOf(BuildContext context)通过Theme.of(context).extension<MooTokens>()取回当前 token,供各页面使用。
单元测试 next-flutter/test/unit/p6_capture_test.dart 中专门有一条测试验证"每种风格使用独立 token 而非复用 modern":它逐项断言quiet.workspace、hero.sidebar、smartisan.accent、miui.accent、claude.workspace都isNot对应位置的modern值。这说明"不是假开关"是有测试约束的设计事实。
3.3 主题构建:Token 与 ColorScheme 汇合
buildTheme(...)(同样位于 theme.dart)负责把 token 与 Material 3 的ColorScheme结合:
final tokens = tokensFor(style, brightness); final scheme = ColorScheme.fromSeed( seedColor: accent ?? tokens.accent, brightness: brightness, surface: tokens.surface, );可以看到ColorScheme.fromSeed的种子色优先使用用户强调色accent,未指定时才回退到当前风格 token 的 accent;scaffoldBackgroundColor直接取tokens.workspace。同时MooTokens通过extensions: [tokens.copyWith(accent: accent ?? tokens.accent)]挂进 ThemeData,供全局组件读取。因此强调色选择确实会"进入ColorScheme"(ADR 原文表述),同时也会覆盖 token 的 accent 通道。
主入口 next-flutter/lib/main.dart 在构建MaterialApp时分别调用buildTheme(brightness: Brightness.light/dark, ...),并把controller.settings.interfaceStyle和_accent(controller.settings.accentColor)传入;themeMode由ThemePreference(system/light/dark)决定。
3.4 字体缩放
buildTheme还实现了全局字体缩放:以 13px 为基准(final factor = uiFontSize / 13),对 Material 的 display/headline/title/body/label 全套文字样式统一乘系数,并强制套用tokens.textPrimary作为前景色。这对应设置中的「界面字号」滑块(11~18)。
四、强调色:6 个预设 id 与旧值兼容
ADR 明确写有:强调色 6 个预设 id 会进入ColorScheme,且旧值#4f83cc仍能解析。这两条都在 next-flutter/lib/app/settings.dart 有直接实现:
const accentColorPresets = { 'yellow': '#e0b22b', 'coral': '#de8f7d', 'blue': '#4f83cc', 'green': '#4e9275', 'red': '#c96761', 'purple': '#8a72b5', }; String resolveAccentHex(String value) { if (accentColorPresets.containsKey(value)) return accentColorPresets[value]!; if (RegExp(r'^#[0-9a-fA-F]{6}$').hasMatch(value)) return value; return accentColorPresets['blue']!; }resolveAccentHex的解析顺序是:
- 命中预设 id(如
blue)→ 返回预设十六进制; - 否则若匹配
#RRGGBB格式(如旧配置里的#4f83cc)→ 原样返回,从而保证历史配置可解析; - 兜底返回
blue(#4f83cc)。
设置页 next-flutter/lib/features/settings/settings_page.dart 的「外观」分类中用六个圆形色块渲染accentColorPresets,点击即把accentColor写为预设 id;main.dart里的_accent再通过resolveAccentHex把它变成Color喂给buildTheme。整条链路(设置项 → 持久化 → 解析 → ColorScheme 种子 → token accent)构成了一个真实生效的强调色系统。
五、导航模式:classic 默认,grouped 有视觉,card 未实现
导航模式在 settings.dart 中定义为:
enum NavigationStyle { classic, card, grouped }在 next-flutter/lib/features/workbench/workbench.dart 的侧边栏渲染中,只有两种模式有实际分支:
classic(默认):工具项按toolGroups顺序平铺成列表,不显示组标题;grouped:在自定义组(customGroups)与内置组(toolGroups)之前渲染组名标题(tokens.textSecondary的 11px 小字);card:代码中没有对应的样式分支,与 ADR 记录的"card 尚未单独视觉"一致。
需要留意的是,侧边栏只有在未折叠(!collapsed)且未开启「隐藏导航标题」时才显示文字,折叠态(宽度 84)下只保留图标,这是与 next-flutter/lib/features/settings/settings_page.dart「布局」分类中hideNavigationTitles、showRecent、compactNavigation等开关共同作用的。
六、快捷键体系:双平台 LogicalKeySet 映射
ADR 记录的快捷键全部通过 Flutter 的Shortcuts+LogicalKeySet实现,macOS 用meta(⌘),其他平台同时注册control,因此同一套代码在两类键盘上都能触发。各快捷键的落点如下:
| 快捷键 | 作用 | 实现位置 |
|---|---|---|
| ⌘/Ctrl+K | 打开工具搜索 | workbench.dart_SearchIntent;另在 main.dart 的CallbackShortcuts中兜底绑定 |
| ⌘/Ctrl+, | 打开设置 | workbench.dart_SettingsIntent |
| Escape | 关闭浮层 | workbench.dart_EscapeIntent(调用controller.closeOverlays) |
| ⌘/Ctrl+F | 查找(JSON 工具) | json_tool.dart_FindIntent |
| ⌘/Ctrl+S | 保存(JSON 工具) | json_tool.dart_SaveIntent(对应saveJsonDocument) |
| ⌘/Ctrl+Enter | 格式化(JSON 工具) | json_tool.dart_FormatIntent(对应formatJson) |
侧边栏的搜索按钮 tooltip 会根据平台动态拼接⌘K或Ctrl+K(defaultTargetPlatform == TargetPlatform.macOS),设置页「快捷键」分类中也以⌘/Ctrl + K、⌘/Ctrl + ,的格式展示了主要组合,这正是 ADR 所述"macOS 显示 Command"的 UI 呈现。
从源码结构看,这类meta + key与control + key成对注册的写法同样复用在编辑器(next-flutter/lib/design/widgets.dart 中的撤销/重做meta/control + Z、meta/control + shift + Z)、JSON 工具与快捷笔记(quick_note_page.dart 的 F/S/Z)中,是项目统一的快捷键模式。
七、分离窗口:同 engine 状态机而非原生 NSWindow
ADR 最后一条约束了分离窗口的实现边界:P2 阶段采用"同一 engine 的状态机",而不是原生独立 NSWindow。源码中的佐证是 next-flutter/lib/core/window/session_transfer.dart 的SessionCoordinator:它用一张_owners表维护"每个 session 当前由哪个 window 持有写入权",通过beginTransfer/ack/abort三个操作完成单写者会话的移交(beginTransfer会校验"源窗口必须是写入所有者",ack校验目标窗口与修订号匹配后才更新所有权)。
在应用层,AppController通过detachedToolIds集合标记"已分离"的工具(见 app_controller.dart 及 workbench.dart 的_navTile:分离工具带open_in_new小图标,长按侧边栏项可在 detach/dock 间切换)。也就是说,"分离"在 P2 是通过 workbench 内的状态与 SessionCoordinator 的会话所有权管理来实现的,与原生多窗口渲染是两个不同阶段的能力。
八、配置项速查与进阶阅读
8.1 与 UI 相关的可配置项一览
以下配置项在 settings.dart 中均有默认值与 JSON 持久化实现,并可在设置页的「外观 / 布局」分类中操作:
| 配置字段 | 默认值 | 可选值 / 范围 | 说明 |
|---|---|---|---|
theme | system | system/light/dark | 决定ThemeMode |
interfaceStyle | modern | modern/quiet/hero/smartisan/miuiV5/claude | 切换整套 surface/强调色 token |
accentColor | blue | yellow/coral/blue/green/red/purple或#RRGGBB | 作为 ColorScheme 种子并覆盖 token accent |
uiFontSize | 13 | 11~18 | 全局界面字号缩放基准 |
navigationStyle | classic | classic/card/grouped | card目前无独立视觉 |
compactNavigation/hideNavigationTitles/showSidebarDivider | false/false/true | 布尔 | 侧边栏显隐细节 |
sidebarWidth | 248 | 220~280(clamp) | 侧边栏宽度 |
8.2 深入阅读源码
- 主题与 Token:next-flutter/lib/design/theme.dart
- 设置模型与强调色解析:next-flutter/lib/app/settings.dart
- 工作台与快捷键绑定:next-flutter/lib/features/workbench/workbench.dart
- 设置页各分类实现:next-flutter/lib/features/settings/settings_page.dart
- 应用入口与主题装配:next-flutter/lib/main.dart
- 会话移交状态机:next-flutter/lib/core/window/session_transfer.dart
- 风格独立性的测试约束:next-flutter/test/unit/p6_capture_test.dart
九、小结
ADR 007 实际上为 MooTool Next Flutter 划定了一条清晰的界面路线:工具页只做沉浸式内容区、主题体系用语义化 Token 支撑六套真实风格与可配置强调色、导航以 classic 为基线逐步演进、快捷键统一走双平台LogicalKeySet映射,而分离窗口在 P2 以同 engine 状态机先行。这些约定在仓库中均有对应源码、设置入口与测试三重印证,阅读本文后,你可以直接在设置页验证风格/强调色/导航模式的真实行为,也可以顺着上文给出的文件路径继续跟踪每一层实现。
- 桌面应用
- 开发工具
【免费下载链接】MooTool
Handy tool set for developers
相关推荐
open-design 设计系统实战:Spotify 近黑沉浸式暗色主题完整规范与实现
open design 设计系统实战:Spotify 近黑沉浸式暗色主题完整规范与实现 本篇文章基于 open design 仓库内设计系统包 design s
人工智能AI Agent前端AI 技能设计系统JupyterLab 用户界面完全指南:菜单栏、侧边栏、主工作区与快捷键体系
JupyterLab 用户界面完全指南:菜单栏、侧边栏、主工作区与快捷键体系 JupyterLab 是一个面向交互式、探索式计算环境的现代 Web 前端,其界面
前端后端数据科学开发工具探索智慧的界面设计:Sofia——打造沉浸式的Android体验
探索智慧的界面设计:Sofia——打造沉浸式的Android体验 在追求完美用户体验的今天,每一个细节的优化都能让用户感受到产品的温度。于是,我们迎来了名为“S
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考