Uh oh!
There was an error while loading. Please reload this page.
refactor: adopt official Astryx desktop shell - #1732
Merged
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Astro-Han added a commit
that referenced
this pull request
Aug 2, 2026
Nothing draws a line between the session rail and the content column, by design: Astryx ships a divider only on `AppShell variant="section"` and Maka runs "surface" (#1732). The separation is meant to come from the material — `--surface-canvas` behind the rail, `--background` on the content — which is exactly what the token block has claimed since the gray-plate/white-card model landed. The step was too small to deliver it. `l - 0.024` resolves to #f7f7f7 against white: six sRGB levels, below what reads as a second surface on most displays. Until now nobody saw the miss, because Astryx painted its own opaque surface over the frame plate; this branch makes the shell transparent so the plate finally shows, and what showed was almost nothing. 0.045 is not a taste pick. It is the surface→body step Astryx itself ships (#ffffff L1.000 → #f1f1f1 L0.958), and it puts light mode within a hair of the dark step (0.065) this file has carried all along. Dark stays where it is — it was tuned against a dark plate, reads fine, and is not the boundary anyone reported losing. Not variant="section": a hairline plus a wash is two mechanisms for one job, and section's divider is unconditional, so it would draw a rule down the 48px icon rail — the same orphan line this branch just removed above Settings.
Astro-Han added a commit
that referenced
this pull request
Aug 2, 2026
Nothing draws a line between the session rail and the content column, by design: Astryx ships a divider only on `AppShell variant="section"` and Maka runs "surface" (#1732). The separation is meant to come from the material — `--surface-canvas` behind the rail, `--background` on the content — which is exactly what the token block has claimed since the gray-plate/white-card model landed. The step was too small to deliver it. `l - 0.024` resolves to #f7f7f7 against white: six sRGB levels, below what reads as a second surface on most displays. Until now nobody saw the miss, because Astryx painted its own opaque surface over the frame plate; this branch makes the shell transparent so the plate finally shows, and what showed was almost nothing. 0.045 is not a taste pick. It is the surface→body step Astryx itself ships (#ffffff L1.000 → #f1f1f1 L0.958), and it puts light mode within a hair of the dark step (0.065) this file has carried all along. Dark stays where it is — it was tuned against a dark plate, reads fine, and is not the boundary anyone reported losing. Not variant="section": a hairline plus a wash is two mechanisms for one job, and section's divider is unconditional, so it would draw a rule down the 48px icon rail — the same orphan line this branch just removed above Settings.
Astro-Han added a commit
that referenced
this pull request
Aug 2, 2026
Nothing draws a line between the session rail and the content column, by design: Astryx ships a divider only on `AppShell variant="section"` and Maka runs "surface" (#1732). The separation is meant to come from the material — `--surface-canvas` behind the rail, `--background` on the content — which is exactly what the token block has claimed since the gray-plate/white-card model landed. The step was too small to deliver it. `l - 0.024` resolves to #f7f7f7 against white: six sRGB levels, below what reads as a second surface on most displays. Until now nobody saw the miss, because Astryx painted its own opaque surface over the frame plate; this branch makes the shell transparent so the plate finally shows, and what showed was almost nothing. 0.045 is not a taste pick. It is the surface→body step Astryx itself ships (#ffffff L1.000 → #f1f1f1 L0.958), and it puts light mode within a hair of the dark step (0.065) this file has carried all along. Dark stays where it is — it was tuned against a dark plate, reads fine, and is not the boundary anyone reported losing. Not variant="section": a hairline plus a wash is two mechanisms for one job, and section's divider is unconditional, so it would draw a rule down the 48px icon rail — the same orphan line this branch just removed above Settings.
Astro-Han added a commit
that referenced
this pull request
Aug 2, 2026
…rail (#1876) * fix(desktop): paint column surfaces through a transparent titlebar overlay Stop using AppShell topNav as a full-width chrome row so sidebar canvas and session --background extend to the window top (Codex/Claude/Cursor). Keep a single absolute drag overlay with no-drag action clusters, Windows WCO gutters, and 16px secondary ghost icons aligned with SideNav chrome. * feat(desktop): collapse the session rail into a 48px icon rail Continuous Collapse: the 48px rail stays in flow and paints ink only, with `.appFrame` flipping to the plate background when collapsed, so the transparent titlebar reads as one surface with the column instead of a chrome bar. Session rows share the nav items' left edge: `.maka-list-stackContent` no longer adds a second inline inset on top of SideNav's `scrollable` padding, and its grid track is `minmax(0, 1fr)` so a long title cannot push the row past the rail and get its end actions clipped. `.maka-session-item-label` is block-level flex, not inline-flex. An inline box is shrink-to-fit with a min-content floor, which for a nowrap title is the whole string — the label then outgrew its slot and painted over the row meta instead of ellipsizing. Width easing is scoped to collapse/expand via `data-easing`. A standing width transition also caught the per-pointer-move updates from the resize handle and made the drag lag the cursor. * fix(desktop): restore Astryx's icon scale under the 13px product root Astryx sizes icons in rem so they track the root font-size, and documents the scale as its px-equivalents at a 16px root: 12 / 16 / 20 / 24. Maka's root is 13px, so every icon Astryx renders lands at 81% of that — 13px sitting next to the 16px lucide icons the product hands to Astryx slots by absolute size. The nav rail showed it worst: 新任务 / 扩展 / 定时任务 read visibly smaller than the same-family icons one settings page away. The 13px type scale is deliberate; the icon scale was never meant to follow it, so restate Astryx's own intent in px at the renderer mounts rather than move the rem base. Class-on-class beats StyleX's single-class rules without !important. * fix(desktop): drop the footer hairline on the collapsed rail The rule that was supposed to do this targeted `.maka-session-panel-footer`, whose border is already `0 !important` — it never had a border to clear. The hairline is drawn one level up, on the sticky-bottom host that separates the scrolling history from the footer. At 48px there is no history column left to separate, so the line reads as an orphan rule floating above the Settings icon on an otherwise ink-only rail. Scope the collapsed override to the rule that owns the border in sidebar.css rather than reaching for it from the shell. * docs(desktop): stop citing contracts that no longer exist maka-tokens.css claimed five static guards enforced its scales: motion-token-converge, icon-system-contract, the spacing adjacency pin, and governance contract #406. All of them went out with the 149 source-scanning tests in #1724. A comment that promises a guard nobody runs is worse than no comment — it reads as "the build will catch this" while nothing does. The rules themselves stay; only the enforcement claims change to what actually holds them: convention and review. Also record why chat-message.css reaches for an Astryx duration instead of the product scale. It is not a leak: Astryx ChatToolCalls opens its own group with `grid-template-rows --duration-medium --ease-standard`, so a detail row that expands beside one has to share that clock. Without the note the next reader "fixes" it onto --duration-large and desyncs the two disclosures. check-dead-css: allowlist astryx-icon and astryx-app-shell-sidenav, both themeProps classes that exist only at runtime. * chore(desktop): delete orphan tokens and let check-dead-css see them Sixteen tokens in maka-tokens.css had no reader left anywhere: the --action CTA pair, --toast-accent, --bot-brand-default, --brand-deep-hover, --system-alert-accent, two --color-* alias tiers, --shadow-modal, --focus-glow-width, --scale-hover, --ease-drawer, --font-serif, --h-toolbar, --h-list-header, and --w-sessionlist (session width has been React state for a while). Their surrounding notes claimed live consumers, so the comments went with them. Ten unused tokens stay. A rung of an ordered scale outliving its last consumer is not rot — deleting the middle of the z-index or control-height ladder is exactly what invites the next bare number. RESERVED_SCALE_TOKENS carries them with the series each belongs to. check-dead-css now sweeps tokens alongside classes, so this converges instead of drifting back. Two consumer surfaces the class sweep never needed are in scope for tokens: packages/ui stylesheets, and stories — a story composing a surface out of the design vocabulary is a real reader, though a product class only a story mentions is still dead. Verified both ways: an injected orphan trips --check in either declaration style, and the live renderer resolves every var() after the deletions. * fix(desktop): give the session column a plate you can actually see Nothing draws a line between the session rail and the content column, by design: Astryx ships a divider only on `AppShell variant="section"` and Maka runs "surface" (#1732). The separation is meant to come from the material — `--surface-canvas` behind the rail, `--background` on the content — which is exactly what the token block has claimed since the gray-plate/white-card model landed. The step was too small to deliver it. `l - 0.024` resolves to #f7f7f7 against white: six sRGB levels, below what reads as a second surface on most displays. Until now nobody saw the miss, because Astryx painted its own opaque surface over the frame plate; this branch makes the shell transparent so the plate finally shows, and what showed was almost nothing. 0.045 is not a taste pick. It is the surface→body step Astryx itself ships (#ffffff L1.000 → #f1f1f1 L0.958), and it puts light mode within a hair of the dark step (0.065) this file has carried all along. Dark stays where it is — it was tuned against a dark plate, reads fine, and is not the boundary anyone reported losing. Not variant="section": a hairline plus a wash is two mechanisms for one job, and section's divider is unconditional, so it would draw a rule down the 48px icon rail — the same orphan line this branch just removed above Settings. * refactor(desktop): let AppShell own the column materials The column boundary was a product invention held together by two `!important` rules: paint `--surface-canvas` on `.appFrame`, then force AppShell and its sideNav slot transparent so the plate reads through them. Every layer in between had to stay transparent forever, and Astryx's own material tokens sat unused underneath. Astryx ships this exact model. `variant="elevated"` — its default — paints the nav column `--color-background-body` and the content column `--color-background-surface`; with no topNav there is no radius or backdrop, just the two materials. Maka ran `"surface"`, the one variant that paints both columns the same and draws no divider, which is why there was nothing to see. Taking Astryx's paint means fixing whose colors it paints with. Its neutral pair is static light-dark(), so it cannot follow Maka's six switchable palettes — and in dark mode the two systems disagree outright: Astryx's surface is #262626 against the product's #171719, so the nav column rendered LIGHTER than the content it navigates. makaTheme.ts now points both material tokens back at the palette. Direction is deliberate and opposite to the type scale above it: Astryx's scale covers everything Maka needs from type, while its neutral pair is a fraction of a palette that also carries status, chat, and per-theme colors. Dark's plate step joins light's 0.045. The old 0.065 was never seen on the shell — Astryx painted over the frame plate until now — and against #171719 content it renders a near-black #09090b rail. Continuous Collapse survives as the one rule that overrides a column material: collapsed, the 48px rail takes the content surface, because the traffic lights are wider than the rail and a wash boundary would run a seam through them. Measured in Storybook (Chromium, sampled pixels), both schemes, both states: light expanded nav #f0f0f0 content #ffffff light collapsed nav #ffffff content #ffffff dark expanded nav #0d0d0f content #171819 dark collapsed nav #171719 content #171819 * fix(desktop): stop tooltips from swallowing clicks under them Astryx tooltips are text popovers with no interactive content, but they leave pointer-events at auto, so an open tooltip is a hit target. Anchored to a control in the titlebar there is no room above it, so the layer flips below the window's top edge and lands on the SideNav's first row — 86×28 of it, measured live, directly over 新任务. The E2E caught it deterministically: click 展开侧边栏, and the pointer stays parked on its trigger, so the tooltip that opens never closes and the next click has nowhere to land. A person hits the same edge more briefly on the way down to the first nav row. It surfaced now because 新任务 moved into the rail in this branch; before, the row under that tooltip was not a target. A tooltip is an affordance, never a target. One unscoped rule — the popover renders in the top layer, where a mount-scoped selector is not reliably in the chain — and no !important, since StyleX declares no pointer-events of its own. While here: keep the type-scale comment in makaTheme.ts adjacent to `typography`. The materials block landed between them last commit. * feat(desktop): split the columns with a hairline and a quieter wash Sampled the two apps this shell is measured against, by scanning a pixel row across their column seam: Cursor nav #edeeef line 220 content #f6f6f6 ΔL 0.025 Codex nav ~#eeefef line 210 content #ffffff ΔL ~0.010 Maka nav #f0f0f0 (none) content #ffffff ΔL 0.045 Both draw a 1px rule, and both keep the wash far below what Maka was carrying. Maka's sidebar was never the darker one — it was the lightest of the three — but with no line it had to state the whole boundary through lightness, and a wash that wide reads as a gray area rather than a second panel. So: wash down to 0.025, plus the rule. The line says where the boundary is; the wash only says the two columns are different material. The rule is authored in makaTheme.ts, not as a product override, so AppShell keeps one paint authority — the theme emits it into its own @scope, and the color is the product's --border, the same product → Astryx direction as the materials. Astryx's own divider is not usable here: it is hardcoded to `variant === 'section'`, which also drops the wash entirely, and it is unconditional — it would draw down the 48px icon rail. Collapsed still drops both halves of the edge. The traffic lights measure ~62px against a 48px rail, so any column edge there cuts through the cluster. Live measurements (2x capture, pixel row across the seam): light nav 247 line 224 content 255 dark nav 17 line 38 content 23 * revert(desktop): drop the icon-scale pin, the 13px root is gone This branch pinned Astryx's four icon sizes to px because the product root was 13px and every rem-based icon landed at 81% — 13px next to the 16px lucide icons handed to the same slots. That was true when it was written and is not true now: #1857 landed in the rebase and removed the root pin outright, saying so in maka-tokens.css ("the root font-size stays at the browser default (16px) ON PURPOSE") for exactly the same reason this commit existed. So the pin restates what rem already computes. Measured in Storybook across three stories, with the rule and with it reverted: xsm 12, sm 16, md 20, root 16px, identical either way. Keeping it would leave 34 lines of CSS whose comment asserts a 13px root that main's own token sheet denies — the precise shape of rot the rest of this branch is removing. * refactor(desktop): key the column edge on the elevated variant `base` drew the rule under any variant, including ones that paint the columns differently or draw their own divider. Astryx keys component overrides by prop (`variant:elevated`), which emits `.astryx-app-shell-sidenav.elevated` — verified on the live node, which carries both classes. * test(e2e): lock the column edge in both sidebar states The bug this branch was asked to fix — no visible boundary between the session column and the content column — had nothing holding it. Neither half of the edge is greppable: the material comes from a generated theme file, the rule from a component override inside it, and a CSS grep passes on declarations that never reach the element. So assert the rendered result. Collapsed is asserted too, and asserts the opposite: both halves go away, because the traffic lights are wider than the 48px rail and any column edge there cuts through the cluster. Without that half a reviewer cannot tell the collapsed rail from a regression. Both halves ease between states, so the comparisons poll for the resting value — sampled mid-transition the color comes back as oklab(). Mutation-checked, rebuilding between runs: divider width 1px→0px fails on the border assertion, dropping the collapsed background override fails on the material assertion. * docs(desktop): stop describing tokens this branch deleted The dead-token sweep removed the declarations and left their prose, so the token sheet documented six things that no longer exist: the serif family with its whole section header, a "these three geometry tokens" focus-ring recipe that has two, a transform-amplitude note listing a hover scale nothing uses, and the brand/system-banner tint aliases whose comments dangled above the next section. Also drops the double blank line where --shadow-modal stood. The lucide stroke note is corrected rather than deleted: it justified keeping size per call site by pointing at icon rules in astryx-mount.css, and those were reverted on this same branch when the 13px root that motivated them went away. The reason still holds — Astryx sizes its slot icons through its own props — so the sentence now names that instead of a file that no longer says it. * fix(desktop): give the shell one paint authority and tests that can fail Five independent reviews of this branch converged on two defects it had introduced, both of the same kind: a comment asserting a guarantee the code did not provide. window-titlebar.spec.ts had stopped seeing the class of defect it exists for. The strip became an absolute overlay with default pointer-events, so it is the topmost hit at every point of the band and `elementFromPoint` returns it and nothing else; every control beneath silently failed the "is this reachable" precondition and was skipped. The assertion that used to catch this was inverted in the same change (`band.bottom <= contentTop` became its converse), leaving a form satisfied by exactly the geometry that creates the hazard. Mutation-proved: deleting either column's `padding-top` put 新任务, the workbar tab and 查看上一版本 under the overlay — real 30s click timeouts in three other specs — while this spec passed. The sweep now probes with `elementsFromPoint` minus the strip's own subtree, and splits the judgment: the strip's children are reachable and keep the app-region rules, anything beneath it is a defect outright, since no-drag shapes the OS rect while the click is already lost to the strip's hit-testing. That immediately caught the resize handle, which is positioned against the column box rather than flowing inside it and so kept its top 36px under the strip; it now starts below it. The Astryx neutral ramp was half-migrated. Remapping only the two tokens the shell reads left card, popover, muted and the hairline on the static light-dark() pair, and a ramp with one half palette-driven and the other frozen does not merely drift — it inverts: stock muted is L 0.222 against a --background of 0.18–0.24, so the recessive fill sat at or above the surface it is recessed into, in 8 of 11 dark palettes. Card, Code, ChatToolCalls, Slider and TableRow are the transcript, not chrome. The whole ramp now moves, onto the product's own stated hierarchy; --muted lands on foreground-at-5%, defined relative to whatever it sits on, so the inversion is unrepresentable rather than merely corrected. Also from the reviews, each verified before acting on it: - The tooltip hit-test rule was global, disabling the hover bridge Astryx documents as its WCAG 1.4.13 implementation for all 33 call sites. Scoped to the titlebar, the one place the layer cannot flip into empty space, with the concession stated. - Both new `!important`s rested on "StyleX is unlayered", which this app contradicts: astryx.css is one @layer astryx-base block imported into astryx-components, which product `components` outranks outright. Dropped. The `.astryx-button` colour rule went with them — Icon colours the glyph itself, so a button-level rule never reached it. - The content column had two paint authorities, and the new column-material test sampled the product's copy, so it would have passed with AppShell painting nothing. It samples AppShell's own element now, and the product's background is gone. - `.maka-sidenav-motion` mirrored a width SideNav already owns and then needed `width: 100% !important` to beat it. Deleted; the transition lives on the nav. Its React easing flag went too: cleared on transitionend, it never cleared when no transition ran, leaving every later drag animated — the exact fault it existed to prevent. The gate is now derived from the handle's own `data-resizing`/focus, so it cannot desynchronize. - `data-sidebar-state` had three writers and one reader; `data-modal-background- hidden` had no readers at all. One writer, on the frame. - The Storybook shell omitted `data-sidebar-state`, so the pixel-review surface rendered a collapsed state the app does not have. New locks, each mutation-verified to fail: the 48px collapsed rail (the number the dropped column edge argues from), the transition suppression during resize, and the column materials read off AppShell. Not done, and deliberately: the generated edge selector is a bare `.elevated` class, which Astryx's own themeProps notes advise against — the CLI emits it, so it is an upstream report, not a local fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verification
npm --workspace @maka/ui test— 296 passednpm --workspace @maka/desktop run typechecknpm --workspace @maka/desktop test— 2014 passednpm --workspace @maka/desktop run build-storybooknpm --workspace @maka/desktop run smoke:storybook— 27 story render/play checks passednpm --workspace @maka/desktop run e2e— 93 passedReview focus