fix(desktop): status-color restraint — expected states stop shouting green - #651
Merged
Conversation
…green The 权限与能力 page (and siblings) painted the EXPECTED state green everywhere: granted OS rows wore a green left stripe + green icon fill + green 已授权 badge, enabled capability cards a green border, healthy layers green text, granted chips green pills, the granted summary count a green number — and every toast carried a colored left stripe. None of these were token leaks (all rode --success); they were success-color overuse plus the stripe-on-card template trope. Rule applied (exception-only): the normal state renders neutral; color is reserved for states needing attention (denied/degraded/waiting), tiny dot-tier indicators, transient feedback (copy-成功 flash), and comparative semantics (permission diff old/new, hljs-addition). - toast.css: per-variant left stripes removed — the tinted icon is the single variant signal on a neutral card - permission page: granted/enabled/success de-tinted across rows, cards, chips, layers, summary tiles; denied/not_determined keep their stripes; 已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm) and empty tiles dim like the health page's - health page: healthy tiles/rows keep the default hairline - connections: verified/authenticated cards use default chrome; success badges/pills fall to the neutral base; OAuth logged-in badge neutral - memory: save-summary box neutral card instead of green wash - new settings-permissions visual-smoke fixture so this page finally has a screenshot baseline
jackwener
added a commit
that referenced
this pull request
Jul 9, 2026
…s neutral (#696) 使用统计 and 健康 were the last two settings pages without visual-smoke fixtures — added (settings-usage / settings-health), and the first sweep found: - 使用统计: the amber notice's 显示明细 action was a bare text ghost — outline per the text-buttons-wear-edges rule - 健康: ok/正常 still rendered success-green on chips AND summary tiles, while the same #651 restraint rule already made 权限 已授权 neutral — expected states are neutral; color stays reserved for signals needing attention (提示/警告/错误 keep their tones) Desktop 2296/2296, dead-css clean.
This was referenced Jul 10, 2026
Closed
jackwener
added a commit
that referenced
this pull request
Jul 11, 2026
…mary, honest fade (round 16) (#722) Post-pull discovery sweep over the externally-merged tip (LiteLLM, Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the Goal kill-switch pill which correctly absorbed the earlier review blockers). Three finds, fixed: - 每日回顾 已生成 chip still success-green — the EXPECTED outcome per the #651 restraint rule (健康 正常 and 权限 已授权 are already neutral); failures keep destructive. - 机器人对话 had NO primary at all — 测试并连接 (the form's completion action) promoted from secondary to default. - first-run provider list: the 28px bottom fade left a half-clipped row still half-legible — read as broken clipping; 56px fully veils it. Also re-learned: the desktop test suite does not compile renderer pages (a JSX syntax error sailed through 2309 green tests and only vite/ typecheck caught it) — full typecheck now part of this round's gate. Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
7 tasks
jackwener
added a commit
that referenced
this pull request
Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker The run model-option default read 使用设置中的分析模型 — too long for the compact picker that now rides the PageHeader actions slot (it wrapped to two lines). Shorten to 跟随设置; a run with no explicit override still falls back to the model configured in Settings (behavior unchanged — the sentinel value and bridge mapping are untouched). * feat(daily-review): real IA redesign of the 每日回顾 module page The page was 很乱/很不好用: two floating control rows with unclear ownership, a broken master-detail archive list that left its left column half-empty, a status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the page bottom, and a stats section that vanished entirely on a no-activity day. Rebuild the information architecture (zero data/IPC/behavior change — same props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved): - PageHeader is the page shell: title + subtitle, and the 生成每日回顾 / 生成深度分析 actions ride its actions slot (skills-page pattern). The analysis model select is now a COMPACT generation option in that same cluster, not a page-wide row. Header moves into the panel so the actions can compose with the panel's run state; the bridge-less fallback keeps its own static header. - ONE time-scope row under the header: the 今日/本周/本月 segmented + the day-stepper are one visual cluster (both are time navigation) instead of two widgets at opposite page corners. - 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with honest zeros even on a no-activity scope, plus one inline muted hint. This absorbs the old bottom-of-page orphan line, which is deleted — the stats section no longer disappears into a hole. - 报告 section replaces the broken master-detail with a stacked, newest-first list of full-width report surfaces. Each shows an always-visible meta head (date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the selected report expands its four content sections in place. Status color is exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection lazy body load (getArchive) is unchanged — the archive-body-load contract pins that path. - Empty report state is the EmptyState primitive with a CTA wired to 生成每日回顾 (respects the pending/running guards). - Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated to a non-empty scope (guard shape pinned by the copy-feedback contract). Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface entry follows the rename to .maka-daily-review-report (the surface owns the radius; the expanded body divides with a hairline).
jackwener
added a commit
that referenced
this pull request
Jul 18, 2026
…page onto the house language (#1205) * test(visual-smoke): add module-mcp fixture scenario Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json holding two disabled servers, so the market grid, tab row, hero banner and installed server list all render deterministically for the alignment auditor and CDP capture. enabled:false keeps visual-smoke from attempting real npx / HTTP connections, so rows settle in the neutral 已停用 state. * feat(mcp): polish MCP page onto the house language Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾 redesign, presentation-only (same IPC/props/callbacks): - Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle + edged actions cluster; 添加 MCP is the primary CTA). - Market/installed tabs move onto the shared underline TabsList/TabsTrigger primitive with count pills, matching the skills tab-row rhythm; the search field pins to the tab row's right edge. - Empty + no-results states use the shared EmptyState primitive. - Installed server status is exception-only (#651): a healthy/expected server shows no status color — its label rides plain muted text and a neutral dot; only a real 连接失败 raises a destructive Chip + colored dot. - The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled library-icon tiles (Terminal/Plug/Globe), and the per-template market marks drop their hand-drawn brand SVGs for the catalog text mark on the existing brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A). * feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the @maka/ui/icons lucide funnel so they share one stroke, sizing seam and family. - menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check <svg> for <Check> from ../icons.js (same precedent as model-picker's ItemIndicator), keeping the lucide funnel intact. - icon-governance-contract: a new pin machine-walks packages/ui/src and apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars ban uses) and fails on any <svg> literal in a .tsx outside an audited brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The allowlist is guarded against rot; new offenders fail with a message pointing at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide re-export with zero <svg> literals. * chore(audit): cover module-mcp in the row-alignment auditor The MCP module page now has a visual-smoke fixture; add it to the audit-alignment FIXTURES so the row-alignment governance tool sweeps the polished header, tab row, market grid and installed list too.
jackwener
added a commit
that referenced
this pull request
Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233) * fix(tokens): shift default --info from amber to cool blue (F1) Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's orange h55 — info and warning tiers were indistinguishable. Retune the default light/dark --info to the azure-family blue (h240, matching the blue-info alt themes) so it reads as informational and stays distinct from warning. --info-text stays the same color-mix formula; the 406 contrast contract recomputes dynamically and still passes. * fix(settings): converge hero metadata badges onto Badge secondary (F2) health-center used Badge variant=info while voice used a hand-rolled .settingsFeatureStatusBadge span (blue via --nav-active) — two treatments for the same quiet-metadata role (只读快照 / 本地自检). Both now use Badge variant=secondary (the calm neutral pill, same as plan-reminder's 已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS. * fix(settings): permission 已授权 summary tile neutral not success (F3) The 已授权 summary tile colored an expected steady state success while its own granted row chip and health's 正常 tile are neutral. Switch to tone=neutral per #651 exception-only status color. * fix(ui): route bare empty states through EmptyState primitive (F5) task-ledger empty (当前会话没有待推进任务) now uses the compact inline EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses the card EmptyState with a MessageSquare icon, matching skills/daily-review. Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding .settingsRemoteAccessEmpty override. * fix(plans): neutral next-trigger countdown pill on expected state (F6) The next-run countdown pill was accent-tinted (--nav-active) on an ordinary scheduled state. Make it a neutral foreground wash per #651; colour stays reserved for genuinely exceptional states. * fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2) The 'account' SettingsSection rendered AccountSettingsPage but was never in SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the sidebar showed no highlight, and a persisted 'account' bounced to models on reopen. Its connection list and lone 测试凭据 action duplicated the Models page. - Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and the account-only account-auth-ui.ts + their .account/.auth copy blocks. - Route every health-notice/onboarding/deep-link consumer to 'models'; drop the goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.) - Derive the settings header from getSettingsNavigationCopy(...).sections[section] instead of a nav[0] fallback, so an unrouted section fails at the Record<SettingsSection> boundary instead of silently borrowing a title. - Add contract tests pinning: every SettingsSection is a nav item (no orphans), and the header is keyed by the active section, not nav[0]. * fix(composer): guide the post-skip no-model dead end (U3) After an onboarding skip with zero model connections, Send was disabled with no explanation. Add an inline hint above the composer (一句话 + 前往模型设置 link-button wired to openSettingsSection('models')) and an explanatory title on the disabled Send. The hint renders OUTSIDE the <form> so it never grows the composer's constant footprint (#740), honors the same hidden state, and is theme-aware via tokens. * fix(settings): migrate hand-rolled notice families onto Alert primitive (F4) Consolidate four bespoke notice CSS families onto the shared <Alert>: - .settingsNotice (info + passive) → Alert variant=info / new variant=passive - .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph) - .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action - .settingsHealthError → Alert variant=error Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5 wash, muted text) so passive notices keep their calm look without a CSS fork. Migrates ~18 call sites across 11 files; role=status semantics preserved. Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] / .settingsNoticeAction). .settingsNotice base rule stays for account-settings-page.tsx (owned by a separate change). Contract re-pins: radius-converge drops the two deleted selectors; voice-capture -smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css, knip ×2, audit-alignment all green. * fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6) U4: useSkillInChat now appendText()s the skill invocation instead of setText, so an in-progress draft survives (appendText falls back to a plain set on an empty draft). Re-pin composer-send-guard. U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail (扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title 扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned. (bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.) U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle, theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted). Also prune the dead account-page CSS the retire left behind (settingsAuthContract*, settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList, settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced them. Bind the health-notice label to a local so the static a11y checker sees it. * test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d) 7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/ health, module-mcp, long-transcript) so screenshot review has evidence of them. 7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM — the marker is already on disk so Electron has nothing to flush; the audit measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup regression (per-run user-data dir is under os.tmpdir()). 7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail sheet (needs_reauth) instead of just the 模型 section, so the re-login affordance is what gets captured. Threads a new openConnectionDetailSlug through VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail → overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug, mirroring the existing openProviderCatalog path. * test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1) conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both locales. markdown-body: the internal-nav-link sanitization example used maka://settings/account, now invalid after the account section retire — use maka://settings/models. * test(ui): pin the U3 no-model composer hint + disabled-send title Renders Composer with noModelConnection and asserts the inline hint, the 前往模型设置 link-button, and the explanatory disabled-Send title appear (and are absent by default) in both locales. * chore(ui): cross-wave integration — retire the last settingsNotice remnants Wave A kept the .settingsNotice base rule alive solely for account-settings-page; Wave B retired that page, so the rule and its radius-converge entry go with it.
jackwener
added a commit
that referenced
this pull request
Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274) * feat(ui): extract DataTable primitive from usage stats table Promote the #1252 hairline table recipe out of usage-settings-page into a shared DataTable primitive (@maka/ui) now that it has health + permission consumers. The primitive owns the table markup: muted+medium scoped col headers, first-cell-as-scoped-row-header, hairline row separators, right-aligned tabular-nums numeric columns, and one grow column that absorbs slack while the rest size to content on one line. UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab routing (EmptyState icon+copy) that a table primitive deliberately omits, and delegates the non-empty branch to <DataTable>. Rendering is pixel-identical — every utility class and the settingsUsageTable pin class are preserved. Re-pin: the moved table markup is now guarded by packages/ui data-table.test (renderToStaticMarkup); settings-usage-contract's stats-table assertions follow the split — keep the wrapper's typed-column + EmptyState signature, assert delegation to <DataTable>, and forbid a hand-rolled <table>. * refactor(settings): kill the .settingsAboutPrivacy blue-header dialect The uppercase brand-blue h3 + brand-deep tinted card was a fourth section- header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入 导出 header — the reason 数据's export section wore a blue header. Converge both onto the sanctioned language: - 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the privacy points (a quiet 'just so you know' callout; matches the passive Alert language already on the data page's backup notice). - 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form controls, no card chrome (it's a form, not a callout). Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral gap containers. Re-pin radius-converge (drop the stale selector) and settings-app-info (name now scopes at the section) contracts. * polish(ui): converge search pre-search hint + fix gateway 5-tile grid - search-modal: route the pre-search guidance line through the shared EmptyState inline primitive instead of a bare <p>, so the 'start typing' hint uses the sanctioned empty-state language (keeps the placeholder pin class so layout is unchanged). - open-gateway: the posture strip has five metric tiles but reused the four-column .settingsUsageSummary grid, orphaning the fifth on a second row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2) wrap when the pane narrows. * polish(permissions): drop the OS-row status stripe (#651) Each OS-permission row already shows its state as a Badge; the left-edge status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status channel, and the amber stripe read as a standing alarm on an expected waiting state. Remove both stripe rules and the now-orphaned position:relative anchor; the row's Chip/text is the single state signal (the denied icon tint stays as the one exception accent). * refactor(providers): converge .providerRootHeader onto SectionHeader The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3 + muted help + far-right count) — a fourth section-header dialect. Converge both onto the shared SectionHeader primitive: title + subtitle, and the connection count rides SectionHeader's count slot (tabular-nums baked in). Extend SectionHeader with an optional titleId so the catalog section keeps its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin: tabular-nums-converge (drop the removed selector, add a SectionHeader primitive pin) and provider-navigation (catalog title now on SectionHeader via titleId). * polish(settings): converge health/permission onto dense shared-language rows Polish wave (wave 2) — kill the bordered-block dialect on the Health and Permission Center pages and the redundant gray intro banners. - Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row primitive inside one hairline card; prose message + detail keep stacked secondary lines, status is a squared Chip (exception-only color via its tone scale), send/capability blockers are exception Chips. Meta on one tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS. - Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided rows in one card matching the OS permission list above; the nested gray boxed .settingsCapabilityLayers dl becomes structured secondary lines (no nested surface). readiness Badge -> Chip. Kept the dl + aria-label and the diagnostics collapse. - Item 5: the second gray-banner PageHeader on each page (.settingsHealthIntro / .settingsPermissionIntro) restating the page title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh moved into the action slot, banner chrome dropped. Re-pins: radius-converge SELECTOR_TIER drops the retired .settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius entries and adds the new .settingsCapabilityList/.settingsHealthSignalList card entries. roadmap-cleanup + capability-audit contracts unchanged. Verified light+dark via direct CDP over settings-health / settings-permissions. Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css, audit-alignment (settings-permissions clean) all green. * test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept role=group + aria-label, but the network-gateway contract's regexes pinned the old settingsUsageSummary class name — the one re-pin the wave missed. Also corrects the earlier triage: the failure was branch-caused, not pre-existing on main.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').
Diagnosis first: not a token leak
All of these greens ride
var(--success)through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).Rule applied — exception-only status color
Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).
Changes
settings-permissionsvisual-smoke fixture (page had no screenshot baseline)Verification