Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Settings pages speak the Preferences row grammar

Status: implemented
Translation: current

[中文版](2026-09-26-settings-row-grammar.zh.md)

## Abstract

After the flat settings pane shipped, the owner rated each tab: Preferences
good, About fine; Account, General and Billing "very bad"; Appearance and Agent
Roles "odd"; Agents "not great". Read against the code, the good tabs share one
grammar: every group is titled by meaning, and every line is a `CompactRow` with
one answer on the right, built from the shared surface with about six bespoke
styles. The bad tabs each invent their own rows (multi-control record cards,
avatars, badges, trash icons, meters, a fourth type size) and put boxed record
cards next to flat preference rows on one page. Account and General now use the
Preferences grammar throughout. Records become rows too: a name, one line of
state, and one answer (a value, a menu, or one button), with other actions moved
into that menu or the record's own detail. The other tabs are unconverted.

## Diagnosis

Measured in `packages/components/src/components/settings` on `main` (8f4b9f49):

| Tab | Owner | Bespoke StyleX keys | What breaks the grammar |
| --- | --- | --- | --- |
| Preferences | good | 6 | none: titled groups, `CompactRow`s answered by Switches or one Select |
| About | fine | 9 | none |
| Account | very bad | 31 | email as a header aside; machine rows with a badge, an Agent icon stack, "Configure", a folder menu and an icon button; Sign Out mid-page |
| General | very bad | (same file) | members with avatars, a ghost role menu and red trash icons; invitations with mail tiles and two actions; boxed next to flat |
| Billing | very bad | 52 | ten groups with two titles; a 1.125em plan name; meters, perks with accent checks, six badges, text-link actions, a nested scroller |
| Appearance | odd | 12 | untitled first group holding Theme and Language; font size twice with two controls; a terminal preview block |
| Agent Roles | odd | catalog | catalog rows: 12px names under a glyph tile, two badges each |
| Agents | not great | 46 + 22 | provider rows with inline meters and hover-only actions |

Flat versus card was not the cause: Preferences is flat, and the owner rejected
a "remove flat" attempt ("不是这个的问题"). The superseded attempt, PR #997,
polished Account's bespoke layout (a subgrid of machine columns, then a
connected-accounts card) and was closed.

## Decision

- A settings line is a `CompactRow`: a label, an optional helper that says what the
label cannot, and one answer.
- A record is a row too. Machines: the name, "This machine · Online · darwin ·
Private · 6 Agents · 10 directories", and **Manage**, which opens its settings.
Agents, sharing and directories live on that page, so the row's Agent stack,
Configure button and directory menu are gone. Tokens: the note, then preview ·
source · created · last used, then **Revoke**. Members: the name, their email,
and their role as a menu that also removes them. Invitations: the email, the
role, and the status as a menu that copies the link or withdraws the invitation.
- Connected accounts stay as on `main`: one Profile row answered by the row of
provider logos. A per-provider group was tried and rejected by the owner.
- Account's order: Profile (email, name, avatar, connected accounts), My machines,
CLI Token, and Sign-in (password, then Sign out) last.
- On the flat pane, no group on these pages is boxed. A header action that does
something is text ("Create Token", "Invite members"), not a bare glyph.
- Token dates follow the product language (`toIntlLocaleOrEn`), not the host locale.

## The pane's white page (regression fix)

`surface.canvas` is `colors.elevatedBackground`, meant to be the panel's own fill:
white in light mode, because `[data-settings-surface]` remaps `--card` to
`--popover`. Since #961 the product palette declares `elevatedBackground:
hsl(var(--card))` on the root. A custom property is computed where it is
declared and inherited as that value, so the pane's remap never reached the
token. Measured in the `Settings/DesktopSettingsModal` story, the page was
`rgb(239,239,241)` (the root card) next to a nav at about 94.7%: the nav's step
had vanished and the whole dialog read gray. `productSettingsSurfacePalette`
(`lody-ui-palette.stylex.ts`) re-declares `elevatedBackground` and
`secondaryBackground` on the pane, so they resolve against the pane's own
`--card`. The page measures `rgb(255,255,255)` again, the nav keeps its step, and
dark mode is unchanged because the remap applies only in light mode.

## Limits and next steps

Billing, Appearance, Agent Roles, Agents and the other catalogs (MCP, Shares,
Prompt Shortcuts) still box their records; they come next, one PR each, against
the same table. Removing a member and withdrawing an invitation now take two
clicks (menu, then item) instead of one icon.

## Verification

- `Settings/AccountSettings/DesktopPaneAccount` and `DesktopPaneWorkspace` render
both pages in the pane scope and material. Screenshots were taken before (the
three components swapped back to `main`) and after, in Chinese, in both palettes.
- `tests/account-machines-overview.test.tsx` covers the status line, the local
machine and the single Manage button.
- The pane's fill was measured with `getComputedStyle` in Chromium in both palettes;
jsdom computes no StyleX styles, so no unit test covers it.
- Not verified in the packaged Electron app.

Related: [Settings rhythm and material](2026-09-25-settings-rhythm-and-image-peek.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 设置页统一使用偏好设置的行写法

Status: implemented
Translation: current

[English](2026-09-26-settings-row-grammar.md)

## 摘要

设置窗口改成平铺后,owner 逐个评价了各 Tab:偏好设置好,关于还可以;账号、通用、账单很不好;
外观、Agent 角色很怪;Agents 不是特别好。对照代码,好的 Tab 都用同一种写法:每组有按意思起的
标题,每一行都是 `CompactRow`,右边只有一个答案,全部由公共样式组成,自定义样式只有六个左右。
差的 Tab 各自发明了行(多控件的记录卡片、头像、Badge、垃圾桶图标、进度条、第四种字号),而且在
同一页里把带框的记录卡片和平铺的偏好行放在一起。现在账号和通用两页完全改用偏好设置的写法。记录
也写成行:名称、一行状态、一个答案(一个值、一个菜单或一个按钮),其余操作移进那个菜单或记录自己
的详情页。其他 Tab 尚未改造。

## 诊断

基于 `main`(8f4b9f49)上 `packages/components/src/components/settings` 的代码统计:

| Tab | owner 评价 | 自定义 StyleX 样式 | 破坏写法的地方 |
| --- | --- | --- | --- |
| 偏好设置 | 好 | 6 | 无:分组有标题,每行用开关或一个 Select 回答 |
| 关于 | 还可以 | 9 | 无 |
| 账号 | 很不好 | 31 | 邮箱挂在标题旁;机器行有 Badge、Agent 图标堆叠、“配置”、目录菜单和图标按钮;退出登录在页面中间 |
| 通用 | 很不好 | (同一文件) | 成员带头像、ghost 角色菜单和红色垃圾桶;邀请有信封图标块和两个操作;带框与平铺混排 |
| 账单 | 很不好 | 52 | 十个分组只有两个标题;1.125em 的方案名;进度条、强调色对勾的权益列表、六个 Badge、文字链接操作、嵌套滚动区 |
| 外观 | 怪 | 12 | 第一组无标题,放着主题和语言;字号出现两次、两种控件;一块终端预览 |
| Agent 角色 | 怪 | catalog | catalog 行:12px 名称配图标底块,每行两个 Badge |
| Agents | 一般 | 46 + 22 | Provider 行带内联用量条,操作悬停才出现 |

原因不在平铺还是卡片:偏好设置本身是平铺的,owner 也否定了“去掉平铺”的尝试(“不是这个的问题”)。
被取代的尝试 PR #997 是在账号页已有的自定义布局上继续精修(机器列的 subgrid,然后是已绑定账号卡片),
已关闭。

## 决定

- 设置页的一行就是一个 `CompactRow`:名称,可选的说明(只写名称说不出的内容),和一个答案。
- 记录也是行。机器:名称,“本机 · 在线 · darwin · 私有 · 6 个 Agent · 10 个目录”,以及打开其设置
的**管理**。Agent、共享和目录都在那一页,所以行上的 Agent 图标堆叠、“配置”按钮和目录菜单都去掉了。
Token:备注,然后是预览 · 来源 · 创建时间 · 最近使用,然后是**撤销**。成员:名称、邮箱,角色是一个
菜单,菜单里也能移出工作区。邀请:邮箱、角色,状态是一个菜单,可复制链接或撤回邀请。
- 已绑定账号保持 `main` 的样子:个人资料里的一行,右边是那排服务 Logo。按服务分行的分组试过,被 owner 否掉。
- 账号页顺序:个人资料(邮箱、用户名、头像、已绑定账号)、我的机器、CLI Token,最后是登录
(密码,然后退出登录)。
- 在平铺窗口里,这两页没有带框的分组。标题处执行操作的按钮是文字(“创建 Token”“邀请成员”),不是单独的图标。
- Token 日期跟随产品语言(`toIntlLocaleOrEn`),而不是系统语言。

## 设置面板的白色页面(回归修复)

`surface.canvas` 是 `colors.elevatedBackground`,本意是面板自身的底色:浅色下为白色,因为
`[data-settings-surface]` 把 `--card` 换成了 `--popover`。自 #961 起,产品调色板在根节点上声明
`elevatedBackground: hsl(var(--card))`。CSS 自定义属性在声明它的节点上求值,子节点继承的是算好的值,
所以面板上的替换传不到这个 token。在 `Settings/DesktopSettingsModal` story 里实测,页面是
`rgb(239,239,241)`(根节点的 card),导航栏约 94.7%:导航栏那一档消失,整个 Dialog 发灰。
`productSettingsSurfacePalette`(`lody-ui-palette.stylex.ts`)在面板上重新声明 `elevatedBackground`
和 `secondaryBackground`,让它们按面板自己的 `--card` 求值。页面重新量得 `rgb(255,255,255)`,导航栏
保留深一档,深色模式不变(替换只在浅色下生效)。

## 局限与后续

账单、外观、Agent 角色、Agents 和其他 catalog(MCP、分享、快捷指令)仍然给记录加框;之后按同一张表
逐个改,每页一个 PR。移出成员和撤回邀请现在要点两下(菜单,再点选项),原来是一个图标。

## 验证

- `Settings/AccountSettings/DesktopPaneAccount` 与 `DesktopPaneWorkspace` 在窗口作用域和材质下渲染两页。
前(三个组件临时换回 `main`)后截图,中文,两种配色。
- `tests/account-machines-overview.test.tsx` 覆盖状态行、本机标注和唯一的“管理”按钮。
- 面板底色在 Chromium 里用 `getComputedStyle` 实测两种配色;jsdom 不计算 StyleX 样式,所以没有单元测试覆盖。
- 未在打包后的 Electron 应用中验证。

相关:[设置页的节奏与材质](2026-09-25-settings-rhythm-and-image-peek.zh.md)。
9 changes: 9 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2572,12 +2572,18 @@
"settings.account.machines.privateMachineTooltip": "Only you can access this machine. Its conversations are not visible to other workspace members.",
"settings.account.machines.sharedDirectoryTooltip": "Workspace members can access this directory.",
"settings.account.machines.title": "My machines",
"settings.account.machines.manage": "Manage",
"settings.account.machines.agentCount": "{{count}} Agents",
"settings.account.machines.agentCount_one": "{{count}} Agent",
"settings.account.machines.agentCount_other": "{{count}} Agents",
"settings.account.open": "Open account settings",
"settings.account.signOut": "Sign Out",
"settings.account.title": "Account",
"settings.account.workspaceName": "Workspace",
"settings.account.workspaceNameEditLabel": "Rename workspace",
"settings.account.workspaceNamePlaceholder": "Workspace name",
"settings.account.signIn.title": "Sign-in",
"settings.account.signOutShort": "Sign out",
"settings.profile.title": "Profile",
"settings.profile.name": "Name",
"settings.profile.namePlaceholder": "Your name",
Expand Down Expand Up @@ -2623,6 +2629,7 @@
"settings.profile.password.setupSubmitButton": "Send email",
"settings.profile.password.setupSent": "Check your email for a link to set your password.",
"settings.profile.password.setupFailed": "Failed to send email",
"settings.profile.email": "Email",
"settings.workspace.title": "Workspace",
"settings.workspace.avatar.label": "Workspace logo",
"settings.agent.configurations": "Agent Configurations",
Expand Down Expand Up @@ -3259,6 +3266,7 @@
"workspace.invitations.pending": "Pending",
"workspace.invitations.rejected": "Rejected",
"workspace.invitations.title": "Pending Invitations",
"workspace.invitations.cancel": "Withdraw invitation",
"workspace.invite.description": "Full access to this workspace's projects and sessions.",
"workspace.invite.email": "Email",
"workspace.invite.emailPlaceholder": "name@company.com",
Expand Down Expand Up @@ -3336,6 +3344,7 @@
"workspace.members.roleUpdatedSuccess": "Member role has been successfully updated",
"workspace.members.title": "Members",
"workspace.members.you": "you",
"workspace.members.removeFromWorkspace": "Remove from workspace",
"workspace.newWorkspace": "New workspace",
"workspace.onCloudAndLocal": "Cloud + local",
"workspace.onPureLocal": "Local only",
Expand Down
9 changes: 9 additions & 0 deletions locales/zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2572,12 +2572,18 @@
"settings.account.machines.privateMachineTooltip": "只有你能访问这台机器,其中的对话不会向工作区其他成员开放。",
"settings.account.machines.sharedDirectoryTooltip": "工作区成员可以访问这个目录。",
"settings.account.machines.title": "我的机器",
"settings.account.machines.manage": "管理",
"settings.account.machines.agentCount": "{{count}} 个 Agent",
"settings.account.machines.agentCount_one": "{{count}} 个 Agent",
"settings.account.machines.agentCount_other": "{{count}} 个 Agent",
"settings.account.open": "打开账号设置",
"settings.account.signOut": "退出登录",
"settings.account.title": "账户",
"settings.account.workspaceName": "当前工作区",
"settings.account.workspaceNameEditLabel": "修改工作区名称",
"settings.account.workspaceNamePlaceholder": "工作区名称",
"settings.account.signIn.title": "登录",
"settings.account.signOutShort": "退出",
"settings.profile.title": "个人资料",
"settings.profile.name": "用户名",
"settings.profile.namePlaceholder": "你的名字",
Expand Down Expand Up @@ -2623,6 +2629,7 @@
"settings.profile.password.setupSubmitButton": "发送邮件",
"settings.profile.password.setupSent": "设置密码的链接已发送到你的邮箱。",
"settings.profile.password.setupFailed": "发送邮件失败",
"settings.profile.email": "邮箱",
"settings.workspace.title": "工作区",
"settings.workspace.avatar.label": "工作区图标",
"settings.agent.configurations": "AI代理配置",
Expand Down Expand Up @@ -3259,6 +3266,7 @@
"workspace.invitations.pending": "待加入",
"workspace.invitations.rejected": "已拒绝",
"workspace.invitations.title": "待处理邀请",
"workspace.invitations.cancel": "撤回邀请",
"workspace.invite.description": "对方将获得该工作区项目与会话的完整访问权限。",
"workspace.invite.email": "邮箱",
"workspace.invite.emailPlaceholder": "name@company.com",
Expand Down Expand Up @@ -3336,6 +3344,7 @@
"workspace.members.roleUpdatedSuccess": "成员角色已成功更新",
"workspace.members.title": "成员",
"workspace.members.you": "你",
"workspace.members.removeFromWorkspace": "移出工作区",
"workspace.newWorkspace": "新建工作区",
"workspace.onCloudAndLocal": "云端 + 本地",
"workspace.onPureLocal": "仅本地",
Expand Down
9 changes: 5 additions & 4 deletions packages/components/src/components/settings/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ rolls back — is in the root [AGENTS.md](../../../../../AGENTS.md).
inset); the pane's in-scroll `padding-right` keeps chrome off that column.
- Settings style in StyleX from `surface.ts`/`compact-layout.tsx`. The desktop pane
header names every page; a page hands it actions and a one-line lead through
`settings-page-header.tsx`, never its own title. Inside `settingsFlat` (pane, project
window) preferences are flat under a section rule and managed records keep a card
(`boxed`); elsewhere groups are cards. Group by meaning, no one-row groups; a
helper says what the label cannot. Split master/detail by fill; type: `type.stylex.ts`.
`settings-page-header.tsx`, never its own title. Groups are flat in `settingsFlat`
(pane, project window), else cards. Group by meaning, no one-row groups; a helper
says what the label cannot. Split master/detail by fill; type: `type.stylex.ts`.
- Model pages on Preferences: each line a `CompactRow`, one answer (value, Switch,
Select/menu, button); records too (name, state line; more in its menu/detail).
- `share-management-setting.tsx` lists published static copies via the scoped cloud
query. Ordinary members see their publications; admins see the workspace inventory.
Draft uploads are not published shares. Reuse `useSessionShareLinkActions` for
Expand Down
Loading
Loading