refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

refactor(desktop): rebuild Settings on the Astryx open-group idiom - #1972

Merged
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor
Aug 3, 2026
Merged

refactor(desktop): rebuild Settings on the Astryx open-group idiom#1972
jackwener merged 8 commits into
mainfrom
settings/astryx-refactor

Conversation

@jackwener

Copy link
Copy Markdown
Member

Summary

  • Settings pages move onto the Astryx settings idiom: open row groups (Heading + Divider + edge-to-edge rows), one shared kit (SettingsSection / SettingsRow / SettingsField / SettingsActions / .settingsStatus), no stacked full-width cards
  • Memory page rebuilt around what the user remembers: entries first, direct write-through (no draft/save staging), advanced file/backup/preview behind 展开详情; workspace instruction files move to General
  • Content column is a rounded floating plate again on both the chat shell and Settings; usage gets a 920px data-width budget so its table renders without hidden scroll
  • Storybook gains a zh/en locale toolbar; EN/dark verified across pages
  • Style-shape CSS contract suites deleted (they pinned the previous design); desktop suite 1354/1354 green

Testing

  • typecheck (renderer/storybook/main/preload), biome, format, a11y, copy, dead-css all green
  • node --test dist/main: 1354 pass / 0 fail

Settings pages spoke different layout dialects: implicit-auto card
tracks clipped wide controls (EN SegmentedControl), Item truncated
helper text to one line, and Data/Memory/Voice floated loose forms,
action rows and gray boxes on the page background.
- settings-section.tsx grows the page kit: SettingsRow (wrapping
descriptions, capped end slot), SettingsField, SettingsActions
- rows.css: explicit minmax(0,1fr) card track, owned hairline
dividers, uniform 12px inset; dead selectors removed
- General/Appearance/Data/WebSearch/Memory/Voice/DailyReview/About/
Permission Center/Usage rebuilt onto the kit; Voice loses its
private hero+heading vocabulary; About privacy points stop being
a bold blue Banner flood; usage table scrolls in its own wrapper
- Storybook gains a zh/en locale toolbar so EN-only breakage is
visible in stories
Studied the framework's own settings/settings-dialog templates and
`astryx docs principles/layout`: settings pages are open groups —
Heading + supporting lede + Divider anchor, edge-to-edge rows split
by hairlines — while stacked full-width Cards as page structure,
cards-in-cards, and decorative Badges are named anti-patterns. The
Models page already spoke this language; the other pages spoke a
card dialect. This aligns them:
- settings-section.tsx: the 'rows' body drops its Card for an open
divider-rhythm group; sections gain the template's anchor divider;
page rhythm widens to 32px
- Memory: the nine-button flood becomes save/open/reload + MoreMenu;
instruction and path gray boxes become rows; entries become
edge-to-edge rows (sentence Badge removed); prompt preview becomes
a real section owning one <pre>
- Health / Permission Center: colored StatTile dashboards condense to
one tabular count line; blocker pills become one Banner; status
Badges become StatusDot + text; capability/OS lists lose their Card
- PasswordInput: trailing icon actions move into InputGroupText (the
sanctioned addon segment — bare IconButtons broke the group's caps)
and the visible label stops doubling Astryx's untranslatable
'Required' indicator
- Web Search: credential becomes a full-width field + one action
cluster; Daily Review rejoins the label-left/control-right grammar
- Voice/Data: diagnostics step down from primary; idle states and
guidance stop being blue Banners; mono paths render as full-width
lines under their description
- Dark shell: the sidenav drops its tone-step + hairline edge in dark
(Dark Restraint — light mode already read as one plane)
- check-dead-css: token sweep now includes Astryx's own stylesheet and
StyleX token map (the accent bridge's consumers live there)
…bers
The page led with plumbing (file toggles, instruction files, a nine-item
tool wall) before showing a single remembered thing. Rebuilt from the
user's mental model:
- 记忆: two switches (remember / allow model context), status as a dot
- 已记住的内容 first-class: filter + entries + manual add behind the
section's one action button
- 记忆文件与备份: path row, backups, raw editor — power-user material
moved below the content it serves
- Project instruction files (AGENTS.md/CLAUDE.md/GEMINI.md) are not
memory; the toggle and file rows moved to General as their own group
- Copy speaks user language ("Maka 会在对话中记住你确认过的信息")
- New-code comments trimmed to constraint-only one-liners
- Memory entry actions are direct now: add/archive/restore write MEMORY.md
immediately (single source of truth is the file, not a staged draft);
draft language removed from entry copy
- Entry rows speak user language: title, origin, updated time, content,
archive — ID / copy-reference / locate collapse into a per-entry MoreMenu
- 记忆文件与备份 + model context preview sit behind 展开详情 (collapsed
by default); lead sections stop repeating the page title (memory, health)
- Settings content surface drops its rounded floating plate to match the
chat shell's flat surface
- Sidebar-collapse titlebar button hidden while Settings is open
- Web search: restore the tavily.com application link lost in the field
rework; revert the dark sidenav edge removal (the boundary is by design)
- The content column is a rounded floating plate again — on the chat
shell (.maka-panel-detail over the AppShell canvas) AND on Settings
(.settingsMainPane), same tokens: 4px gap, 12px radius, flush to the
sidebar; the earlier flatten misread the request
- Health: eight signals no longer spread across six one-row sections —
one open list with quiet layer subheads (label + supporting line)
- SettingsStatus idiom: the StatusDot+text cluster used by health /
permission / memory / web-search rows gets a kit class
(.settingsStatus) instead of borrowing .settingsHealthSignalStatus
- Memory add form: cancel clears the inputs
- check-dead-css: astryx-layout-content joins the themeProps allowlist
640px is the right column for settings prose, but the request-log table
is columnar data — at that width the cost/latency/status columns lived
in invisible horizontal scroll. Usage gets a 920px budget (frame-first
region budgeting per the Astryx layout doc); every column now renders
without scrolling.
…gs CSS
The branch redesigns (open row groups, Banner blockers, MetadataList
diagnostics, the restored content plate) invalidated three source-CSS
contract suites that still pinned the old shapes:
- flat-shell-chrome: the content column is a rounded floating plate by
design now — the contract pins the plate (surface token, radius, gap
margins, canvas behind it) instead of forbidding it
- settings-window-floor: dead selectors (.settingsOsPermissionRow,
.settingsPermissionSummary tiles, .settingsHealthSummary grid,
.settingsWebSearchKeyField, .settingsMemoryPromptPreviewHeader,
.settingsCapabilityLayers) replaced with the live equivalents; the
open .settingsRows pins its 0-floor track instead of overflow:hidden
- type-scale: memory.css / health.css / kit CSS moved off raw
font-size/--leading-*/--font-mono declarations onto the --maka-text-*
roles; stale Badge/wrap exemptions removed with their targets
Full desktop suite: 1399/1399.
flat-shell-chrome / settings-window-floor / type-scale /
chat-shell-layout / native-cursor pinned source-CSS declarations to
freeze a visual design. During a deliberate redesign they only assert
that the past is still present — every one of them broke on intended
changes this cycle and none caught a real defect. Deleted; the
functional app-region hygiene contract (window drag regions) stays.
Suite: 1365/1365.
@jackwener
jackwener merged commit 8bb57b0 into mainAug 3, 2026
1 check passed
Astro-Han added a commit that referenced this pull request Aug 3, 2026
#1972 rebuilt the theme picker on Astryx SelectableCard, whose accessible
control is a hidden checkbox, so the group no longer exposes the
radiogroup/radio roles this spec drove. Theme switching itself still
works — a probe confirmed Space on 深色 checks it and flips
`html.dark` — but the spec asserted the old group semantics and its
ArrowDown navigation, neither of which the new picker has.
Settings is mid-rewrite, so re-pinning this journey to whichever roles
the picker happens to expose today buys a contract that is expected to
move again. Removing it is the honest option: the remaining
`remote access` journey keeps settings open → navigate → mutate covered.
Refs #1972.
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… QR panes (#1984)
Follow-up to #1972 covering the two Settings surfaces it left on the old
card dialect:
- claude-subscription-card: the hand-rolled `.settingsConnectionRow`
(9 `data-status` tinted variants) sat inside the otherwise fully
Astryx Providers surface. It now composes Card / HStack / VStack,
with status carried by the Badge + detail line only (status-color
restraint). The gate-read failure becomes a Banner (matching every
other Settings error surface), the quota lines gain a real
ProgressBar gauge (warning >= 75%, error >= 90% utilization), the
paste-code panel becomes Divider + VStack, and the inline paste
error routes through FieldStatus.
- bot-wechat-login: the four hand-tinted `data-tone` QR placeholder
panes become EmptyState (Spinner for loading, check icon on
success, retry actions in the actions slot). The white QR frame
plate stays bespoke — a QR code needs a light background in every
theme.
- connection.css drops from 119 lines to the one `.settingsConnectionMeta`
helper Web Search still uses; `.settingsSubheading` (uppercase eyebrow,
last used by the Claude card) is retired in favor of SectionHeader.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
and the product Storybook smoke (70 catalog renders x 3 viewports).
jackwener added a commit that referenced this pull request Aug 3, 2026
… kit (#1993)
远程接入 was the last page group speaking the pre-#1972 dialect — #1972
did not list it in its rewrite scope, so a user opening it saw a
different product than every other settings page.
- Overview: bespoke page container + section-header dialect + hand-
rolled list grids become SettingsPage → SettingsSection → the kit's
hairline rows. SettingsSection gains a `titleId` prop so the two
sections keep the heading ids their aria-labelledby wiring names
them by. The readiness Badge becomes the shared StatusDot + text
idiom (the title span's aria-label keeps the row's accessible name
byte-identical for the e2e). EmptyState drops its padding-override
class for `isCompact`.
- Detail: the runtime block was a full-width tinted card used as page
structure (the named anti-pattern) — now an open SettingsSection
whose action slot carries the test/connect/restart cluster. The
4→2→1-column <dl> status grid becomes MetadataList, which owns the
responsive collapse the two media queries hand-rolled. The
configuration header dialect becomes a bare-variant SettingsSection
wrapping the mode toggle + credential form; the hand-tinted
quick-setup plate becomes an Astryx Card (a genuine callout).
- Deliberately untouched: `.settingsBotDetailHeader`'s pinned grid
(settings.spec.ts asserts its back → switch → doc link → connect
focus order), the brand plate, both QR frames, and the onboarding
glyphs — documented art, not layout debt.
- bot.css drops ~200 lines of retired dialect; the attention wash,
planned-opacity, and 620px chevron-hiding row behaviors stay.
Verified: desktop typecheck, check-dead-css, check-a11y/copy/console,
product Storybook smoke (71 catalog renders x 3 viewports); e2e
heading-name and focus-order contracts re-checked against the new DOM.
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 6, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
ARE404 added a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit to ARE404/maka-agent that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (apache#1972), and
the settings-page kit (apache#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
jackwener pushed a commit that referenced this pull request Aug 7, 2026
The 外观 page carried four leftovers from the moves that reshaped it —
identity going to 通用 (P2-13), the Astryx open-group rebuild (#1972), and
the settings-page kit (#1991).
- Page root: `AppearanceSettingsPage` wrapped a `ThemeSettingsPage` that
opened a `SettingsPage` of its own, so the page grid nested inside itself
(two `.settingsPageStack` in the DOM). The page IS the theme page, as its
own comment said, so it is now one component with one root. Same defect on
通用, where the identity block was a `*Page` rendered inside another page:
it is a section of someone else's page and is now named, filed, and shaped
as one (`personalization-settings-section.tsx`).
- Grouping: the 14 option tiles were loose in the accessibility tree — the
sections were unnamed landmarks and the visible 编辑器主题 / 产品色调
labels had no programmatic relationship to the grids they head. Sections
now carry `titleId`, and each grid is a `role="group"` named by its label.
- Copy: the nav description still advertised 界面语言 on 外观, a page that
has not had it since P2-13; 通用, which does, never mentioned it. Both
descriptions now say what their page holds.
- Dead copy: `sections.paletteHelp` was defined in both locales and read by
nobody, while the palette section reached into `appearance.persistenceHelp`
for its lede. The palette section now takes its lede from `sections`, the
same namespace the theme section above it uses, and the unread key is gone.
`AppearanceSettingsPage` also stops taking a `settings` prop it only passed
down one level to a component that never read it.
Contract: `astryx-component-behavior` pins one page stack, the four
labelledby anchors, three named groups, no 界面语言 on 外观, and that the
identity block opens no page stack of its own.
Verified: desktop typecheck; format:check; console/a11y/copy checks;
dead-css; 1754 desktop tests; and both pages re-rendered in a real Electron
fixture window (外观 unchanged apart from the two copy lines, 通用 pixel
identical).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener