Actual Budget 侧边导航设计竞赛解析:Sidenav 的现状架构、设计约束与社区驱动重构
【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual
侧边导航(Sidenav)是 Actual Budget 打开应用后最先看到、也最常使用的界面部分,用户通过它往返于预算、报表、日程、账户之间。本文以 Actual Budget 官方发布的设计竞赛公告(design-competition-sidenav.md)为核心骨架,结合仓库中packages/desktop-client/src/components/sidebar/的真实源码实现,解析 sidenav 的现有功能结构与设计约束,并完整梳理竞赛的参赛流程、评选机制与后续落地路径。读完本文,你将理解 Actual Budget 导航栏的模块划分、账户列表的复杂状态机,以及社区如何通过一次设计竞赛直接参与核心 UI 的重构。
一、竞赛背景:为什么重设计侧边导航
在 Actual Budget 中,sidenav 承担着最主要的导航职责:它是用户在预算、报表、日程、账户之间切换的唯一入口,也是每次打开应用时第一眼看到的界面。官方将其定义为“应用中使用频率最高的部分之一”,因此团队决定发起一场面向社区的设计竞赛,让社区来主导导航栏的视觉与交互重构。
竞赛的两项核心奖励明确了这次活动的性质——不是一次简单的征集,而是真实的产品共建:
- 排名前 10 的设计可获得 Actual Budget 官方周边(swag);
- 最终获胜设计将被直接实现进应用,随版本发布给所有用户。
这一点在后继公告中得到印证:获胜公告(sidenav-design-winner.md)确认了冠军得主,并说明"工作将于近期开始",即获胜设计真正进入了开发管线。
二、Sidenav 的现状:从源码看导航栏的真实结构
要设计好一个导航栏,首先要理解它当前承载了什么。从源码看,侧边导航的实现集中在 components/sidebar 目录,入口为 Sidebar.tsx,其布局自上而下分为四个区域。
2.1 预算名与浮动切换(BudgetName + ToggleButton)
侧边栏顶部展示当前预算文件名称(BudgetName),并提供一个浮动模式切换按钮(ToggleButton)。浮动模式由全局偏好floatingSidebar控制,启用后侧边栏以悬浮层形态覆盖在内容之上,移出时自动隐藏。
2.2 主导航(PrimaryButtons)
核心功能导航由 PrimaryButtons.tsx 渲染,文档中提到需要覆盖的核心导航项与源码一一对应:
| 导航项 | 路由 | 图标 |
|---|---|---|
| Budget(预算) | /budget | SvgWallet |
| Reports(报表) | /reports | SvgReports |
| Schedules(日程) | /schedules | SvgCalendar3 |
| More(更多,可展开) | — | 展开/收起箭头 |
| └ Payees(收款方) | /payees | SvgStoreFront |
| └ Rules(规则) | /rules | SvgTuning |
| └ Bank Sync(银行同步) | /bank-sync | SvgCreditCard |
| └ Tags(标签) | /tags | SvgTag |
| └ Settings(设置) | /settings | SvgCog |
注意两个值得设计的细节:
- "More" 折叠面板:Payees、Rules、Bank Sync、Tags、Settings 被收纳在可展开的 "More" 菜单中,且当当前路由命中其中任一子页时会自动展开(源码第 35-47 行的
isActive判断)。 - 条件渲染的 Bank Sync:
Bank Sync项仅当同步服务器可用时出现(syncServerStatus !== 'no-server'),本地纯离线模式下不会显示——这体现了"配置驱动导航"的思路。
2.3 账户列表(Accounts)
账户列表是 sidenav 中最复杂、信息密度最高的区域,由 Accounts.tsx 实现,恰好对应文档中"账户列表是开放式的"这一约束。其结构为:
- All accounts:汇总全部账户,显示总余额;
- On budget 分组:标题行 + 预算内账户列表,每项显示实时余额;
- Off budget 分组:标题行 + 预算外账户列表;
- Closed accounts:可折叠的已关闭账户列表,由本地偏好
ui.showClosedAccounts控制显隐。
每组数据分别来自独立的 hooks(useOnBudgetAccounts/useOffBudgetAccounts/useClosedAccounts),余额通过 spreadsheet binding(如bindings.allAccountBalance()、bindings.accountBalance(account.id))实时计算——这正是文档中"账户余额常内联显示"这一设计要点背后的数据机制。
2.4 账户行的状态矩阵
单个账户行由 Account.tsx 渲染,其状态之丰富,为设计者划定了明确的"信息表达"考题:
- 余额内联:通过
CellValue绑定实时财务数值,悬停可查看余额历史图(BalanceHistoryGraph); - 同步状态:行首的圆点指示器用颜色区分状态——
pending(同步中,sidebarItemBackgroundPending)、failed(失败,sidebarItemBackgroundFailed)、正常(sidebarItemBackgroundPositive),未连接银行时圆点透明隐藏; - 未读加粗:
updated状态会将账户名加粗并着色(sidebarItemTextUpdated),提示有未读新交易; - 选中态:左侧 4px 强调边框 + 主题色文字(
sidebarItemAccentSelected); - 拖拽排序:账户行支持拖拽调整顺序,调用
useMoveAccountMutation持久化; - 右键菜单:悬停可展开 Tooltip,提供重命名、关闭/重新打开账户、切换余额历史图等操作。
从源码看,账户类型判定链为closed → offbudget → onbudget,这意味着已关闭、预算外、预算内三种账户在视觉上必须可区分——与文档中的约束要求完全一致。
三、设计约束解读:文档要求背后的实现证据
竞赛公告给出了一组"约束而非检查清单"的设计要求,结合源码可以看到每条约束在现有实现中的落点:
| 设计约束 | 现有实现依据 |
|---|---|
| 覆盖核心导航(预算/报表/日程/收款方/规则/设置/银行同步) | PrimaryButtons.tsx 的完整路由表 |
| 账户列表开放式(3 个到 30 个不等) | Accounts.tsx 通过分组渲染 + 滚动容器(overflow: 'auto')容纳任意数量账户 |
| 预算内/外账户可区分 | 源码按account.offbudget分组渲染,并有独立标题行 |
| 余额内联显示 | 每个账户行的CellValuebinding 实时计算 |
| 银行同步状态关键 | 账户行首圆点的 pending/failed/正常三态指示器 |
| 适配亮色/暗色及其他主题 | 所有颜色均取自theme主题对象(如theme.sidebarBackground、theme.sidebarItemText),组件不硬编码色值 |
| 可访问性(键盘导航、焦点态、对比度) | 导航容器声明role="navigation"与aria-label;新增的SidebarRedesign同样保留语义化结构 |
| AI 辅助设计被允许 | 公告明文允许使用 AI 工具参与设计 |
其中主题适配尤为关键:Actual Budget 内置多套主题(见 component-library/themes 下的light.css、dark.css、midnight.css、palette.css),因此任何新设计都必须以主题 token 驱动而非硬编码颜色,否则无法在四套主题下同时成立。
四、正在进行的新版导航:SidebarRedesign 预览
值得设计者注意的是,仓库中已存在一版尚在功能开关之后的新侧边栏实现SidebarRedesign,它与竞赛的推进互为呼应:
- 入口判断位于 components/sidebar/index.tsx:
newSidebarUIEnabled ? <SidebarRedesign /> : <Sidebar />,由功能开关newSidebarUI控制; - 新版目录见 components/sidebar/redesign,包含
SidebarRedesign.tsx、PrimaryNav.tsx、NavRow.tsx、SidebarHeader.tsx、SidebarFooter.tsx、SyncStatusLine.tsx等组件; - 相比旧版,新版导航项改为平铺展示(Budget、Reports、Schedules、Payees、Rules、Bank Sync、Tags 全部一级可见,见 PrimaryNav.tsx),不再使用 "More" 折叠;Bank Sync 仍按服务器可用性条件渲染;
- 新版默认宽度为 270px(
DEFAULT_SIDEBAR_WIDTH),并显式声明了role="navigation"与aria-label="Sidebar",可访问性语义更完整。
这版"新侧边栏"可视为竞赛设计落地前的过渡基线,设计者可以参考其信息架构,同时用更激进的方案超越它。
五、参赛流程与时间线(原文档完整信息)
竞赛的参与方式、时间节点与评选机制如下,全部信息以公告原文为准:
时间线:
- 投稿开放:2026 年 6 月 27 日
- 投稿截止:2026 年 7 月 27 日
- 社区投票:约 2026 年 8 月 3 日开始
- 公布胜者:投票结束后不久
参赛方式:
- 通过官方表单提交设计,可以提交任意多个方案(多个方向请作为独立条目分别提交);
- 精致的 Figma 文件不是硬性要求,带清晰标注的线框图(annotated mockup)完全可接受。
评选流程(四步):
- 投稿:截止日期前通过表单提交设计;
- 内部初筛:截止后由维护者审阅所有投稿,选出最多10 位决赛入围者;
- 社区投票:入围方案以 GitHub Issue 形式公示,任何人可通过 👍 表情为心仪方案投票,投票持续一周;
- 落地实现:得票最高的设计将实现进 Actual Budget。
奖励:
- 获胜设计将被实现并随应用发布给所有用户;
- 前 10 名入围者均可获得官方周边。
从后续公告(sidenav-design-winner.md)可以确认整个流程的真实走向:投票结束后的胜者为 matt-fidd,公告同时说明"我们很可能在构建过程中吸收所有投稿的想法",并坦承"部分想法会被否决、过程中会有反复,这是设计过程的正常部分"——这为设计者提供了非常务实的心理预期。
六、对设计者的实战建议
综合文档约束与源码现状,参与此类导航栏设计时可以重点思考以下问题:
- 账户信息的层级表达:面对 3 个与 30 个账户两种极端场景,分组(on/off budget)与折叠(closed)机制如何在视觉上自然伸缩?余额是否始终内联,还是在窄屏下让位?
- 同步状态的轻量呈现:圆点指示器是目前的状态载体,能否在不增加视觉噪声的前提下让同步中/失败/未读更加直观?
- 主题无关性:设计稿中的所有颜色都应映射到主题 token 体系,确保四套主题下对比度与可读性一致;
- 键盘可达性:主导航、账户列表均需完整支持键盘遍历与清晰焦点态,
role="navigation"的语义不能被破坏; - 信息架构取舍:旧版用 "More" 折叠收纳 5 个子导航,新版平铺展示全部一级项——哪种方式更适合大量账户 + 频繁切换的场景,值得用原型验证。
七、总结
Actual Budget 的 sidenav 设计竞赛是一次典型的社区驱动产品共建:文档界定了"核心导航全覆盖、账户列表开放伸缩、主题适配、可访问性"四条硬约束,而仓库源码则展示了这些约束在真实产品中的复杂实现——实时的余额绑定、三态同步指示、拖拽排序、条件渲染的导航项。对设计者而言,理解这份"现状"是提交合格甚至出彩方案的前提;对开发者而言,components/sidebar 目录连同功能开关newSidebarUI下的SidebarRedesign,共同构成了观察这次重构如何从设计稿走向代码的最佳窗口。
【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考