feat(editor): finish the Author writing surface (#993) - #994
Conversation
The #989-#991 slices made Source the widest pane, but Author still read as an equal-card dashboard with a full IDE strip above it. This carries the writing-tool intent through the material rather than the proportions: - Project is demoted to a file drawer: it stops matching the page height (align-self defeats the grid stretch) and drops the card elevation for a recessed surface with tighter padding. - The section nav leads with the writing destinations and lets the Review destinations recede into a captioned, faint cluster; they stay live links that still switch modes and land on the real pane. - Source becomes a page: no card elevation, a focus-within edge instead, and a readable-measure cap (~80 monospace columns) centered in its grid column, so the pane edge is the page edge and heading, editor, gutter, and status line share one column. width:100% is load-bearing there - a grid item with any justify-self other than stretch sizes to its content, so without it the cap never bounds the page. - The top band quiets: the decorative eyebrow is gone, the product mark and the live connection status share one baseline row, the theme control states only its state, and Author takes a tighter header/nav rhythm than Review. - The long connection sentence collapses into a chip whose honest detail is one activation away. The chip is a real button, so the detail is reachable by keyboard and assistive tech rather than hover only, and connection.status now has a single writer so the short label cannot drift from the sentence it summarizes. Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
SummaryCoverage spans core editor layouts and navigation, keyboard accessibility, responsive behavior, preference handling, and connection/recovery flows. It also exercises edge cases around host outages, repeated failures, unsaved edits, reload state, and rapid navigation, with the observed behavior remaining healthy and intentional. Safe to merge — no PR-attributable regressions, new failures, or previously flagged failures remain, and the exercised product behavior is consistent across normal flows and failure states. The few setup limitations and independently reviewed behavior notes are not merge blockers. Tests run by Ito
Tip Reply with @itoqa to send us feedback on this test run. |
Review corrections to the Author writing surface, plus the structural fix behind them: the scales wrote their order down twice, so the tests and the stylesheet could disagree without anything failing. The app title takes its own step in the type chain instead of the pane-title size it had collapsed onto, the theme control drops an aria-pressed that contradicted its own state label, the page shows one focus ring rather than two, the status chip's live region is text-only like every other one, and the hierarchy suite measures both density modes instead of pinning Review. Type, spacing, radius, and layer each declare their order once in tokens.css. A static lint holds the classification, the names, and the README to those lists; a cascade walk resolves the same lists out of the applied stylesheet, which is the only place a clamp step can be checked at all. The six bare z-index values are now named layers, so the ladder is the only authority on stacking order. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
The declared-scales block is the only copy of each order, but the type scale also carried --type-scale-chain/--type-scale-off-chain with the same lists and no consumer. Drop them, and correct the README's count of the widths scales.spec.ts walks (four, matching the test and fragment).
|
Diff SummaryCoverage spans core editor workflows across Author and Review modes, including navigation, writing, focus, responsive layouts, themes, connection states, and accessibility behavior. It also exercises business rules and defensive edge cases around scale ordering, malformed declarations, validation gates, deferred checks, and mode transitions, with adversarial review of disputed behavior. Safe to merge — the run found no PR-attributable regressions, new failures, or previously flagged failures that remain unresolved; all exercised behaviors passed. The untested prior areas are coverage gaps rather than merge blockers, so they are low-risk follow-up observations. Tests run by Ito
Tip Reply with @itoqa to send us feedback on this test run. |

Agent Completion Report
t3code/editor-residual-flat-993t3code/editor-residual-flat-993(the shared checkout; no separate worktree)3320884d(the Author writing surface),9e19150e(fragment named for this PR),65247bca(review corrections + the declared scales)mainmain, 18 files, +1458/−63):editor/ui/src/styles.css,editor/ui/src/lib/tokens.css,editor/ui/src/App.svelteeditor/ui/src/components/Header.svelte,editor/ui/src/components/SectionNav.svelteeditor/ui/src/lib/state/connection.svelte.ts,editor/ui/src/lib/state/buffer.svelte.tseditor/ui/scripts/check-scales.mjs(new)editor/ui/tests/scales.spec.ts(new),density-modes.spec.ts,reading-hierarchy.spec.ts,safe-editing.spec.ts,section-nav.spec.tseditor/ui/package.json,editor/scripts/test-editor-gate.sheditor/README.md,content/guides/editor.md,docs/changelog.d/994-editor-flat-chrome.mdgit add -A. The working tree separately holds uncommitted CLI-reference work (src/cli.zig,content/reference/commands.md,docs/changelog.d/995-cli-reference-current.md) that is not part of this PR and was left untouched; it is being landed as its own PR.align-self: startdefeats the grid stretch so it stops matching the page height, and it drops the card elevation and heavy edge for a recessed neutral surface with tighter padding.:focus-withinedge instead, and a readable-measure cap (54rem, ~80 monospace columns) centered in its grid column so the pane edge is the page edge and heading, editor, gutter, and status line share one column. The cap is Author-only; Review keeps the wide surface beside its rail.width: 100%is load-bearing: a grid item with anyjustify-selfother thanstretchsizes to its content, so without it the pane shrank to ~520px and the cap never bounded the page.Dark/Light, matching its accessible name), and Author takes a smaller product mark plus tighter header and nav bands than Review. Switching the header toalign-items: centeralso let three baseline-compensation margins be deleted.connection.statusnow has a single writer (setStatus(summary, detail)) plus one exportedHOST_UNAVAILABLE_DETAIL, because the new test caughtbuffer.svelte.tsassigningconnection.statusdirectly: the chip still read "Connected" while its detail read "Local host unavailable", which is exactly the drift the short label must not have.65247bca) — four findings from the external review of this PR, each verified against the source before being acted on. All four were confirmed; none were packet drift.header[data-density='author'] h1used--text-xl, the same token ash2, while the comment above it claimed "the order holds everywhere: h1 (app) > h2 (pane)". Fixed by extending the chain rather than documenting an exception, becausetokens.cssitself says "Extend the chain here instead of adding a local size": a new--text-2xl-compactstep sits strictly between--text-xland--text-2xlat every viewport.aria-pressedalongside a state label. A pressed state presumes a name that does not change with it, so light theme announced as "Light, not pressed". The label is the state here, soaria-pressedis gone, not the label.:focus-withinring plus the textarea's own inset outline. The textarea now keeps no ring inside the page shell.role="status"ineditor/ui/srcis text-only; this one was the outlier, and astatusregion is atomic, so the button was re-announced with the state. The live region is now a text-only span with the chip as a sibling.65247bca):--scale-*list ineditor/ui/src/lib/tokens.css. Nothing else keeps a copy: the tests previously held aSCALE_CHAINconstant, and that duplication is what allowed the app title and the pane titles to disagree while every suite stayed green.--scale-space-basedeclares the spacing rhythm's 0.25rem base rather than describing it in prose, so the lint and the walk read it instead of trusting a comment.z-indexvalues instyles.cssbecame--layer-*names, with unchanged values (nav 5, skip link 10, focus overlay 50, and three component-internal layers 0/1/2). The ladder is now the only authority on stacking order. The three local layers are in the same ladder rather than exempted, because an allowlist would have been the hole in the rule.editor/ui/scripts/check-scales.mjs(run bynpm run check, and reported by the editor gate as an "editor UI static checks" stage) holds the static half: classification of every declared token of each family, listed names existing, ascent of each list — numerically where a value is resolvable without a viewport and reported as deferred where it is aclamp— whole-multiple spacing steps, bare-number layers, each scale token declared once and only intokens.css, everyvar()reference landing on a declared step, no bare-numberz-index, and each documented section naming its scale's list without naming tokens that do not exist. It runs its own self-tests first, so the checker is checked.editor/ui/tests/scales.spec.tsholds the half that needs a viewport: it resolves the same lists out of the applied stylesheet at four widths, and asserts the sticky nav and skip link actually carry the declared layers. This is the only place aclampstep can be checked at all — the static lint reports those two type steps as deferred rather than pretending to verify them.--shadow-1..3) are deliberately not a declared scale: a shadow list has no scalar order for a list to protect.zoom, which does not affect media queries), not by an eyeball dogfood at a real wide viewport — the live preview viewport is 600px. The maintainer dogfood is the acceptance step this PR deliberately does not claim.styles.cssstill holds--focus-size: 1.05rem, an off-scale size. Focus reading typography is deliberately independent of the UI scale, so it is not flagged — which means "no off-scale sizes" has an unstated exception rather than a checked one.clampsteps and confirming the real chrome carries the ladder.npm run check(editor/ui)npm run build(editor/ui)npx playwright test(editor/ui)zig build testgit diff --check./scripts/check-pr-issue-close.sh --body-file <this body>npm run check: pass — 0 errors, 0 warnings; key-hints conformance OK (8 visible hints across 24 Svelte sources); scale conformance OK (type 8 steps with 2 deferred to the browser walk, space 8, radius 4, layer 6; no bare z-index)npm run build: pass — 167 modules transformednpx playwright test: pass — 217/217 across 9 files, including the newscales.spec.tswalk and both-mode heading testszig build test: pass — including the documentation link walkgit diff --check: pass — no whitespace errors./scripts/check-pr-issue-close.sh --body-file: passeditor/ui/dist/andeditor/zig-out/(both git-ignored, built for verification and dogfooding)test-results/(git-ignored)--focus-size: 1.05remis exactly such a value. A baselined ratchet that fails on a newly introduced rawremspacing or size, grandfathering the existing ones explicitly, is the natural follow-up.