Skip to content

Align tables to prose and polish unavailable images, formula toggles, and icon titles - #287

Merged
MaggieAppleton merged 3 commits into
mainfrom
design/authored-block-polish
Oct 7, 2026
Merged

MaggieAppleton merged 3 commits into
mainfrom
design/authored-block-polish

Conversation

@MaggieAppleton

@MaggieAppleton MaggieAppleton commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Tables align to prose; unavailable images adapt to block or inline placement; formula source controls sit in the block corner. Decorative icons no longer show raw asset names as native tooltips.

Integration preserves main’s newer stop/play shapes and ink color, removing only their titles. Two newer icons also needed title removal; the regression test caught both. Reviewed the icon forwarding boundaries, added ImageIcon’s matching case, and renewed exact pins including the finite audit catalogue.

Local checks and types pass. The initial unit run had 503 passes and one title regression; all eight icon tests pass after fixing it. All 46 responsive-content/table/code browser tests pass. Published head 5a49fa59; final GitHub CI is pending.

Current integration: rebased cleanly onto merged #286. Local checks/types and all 37 table/rich-content/interface browser cases pass on the current base; CI caught three remaining navigation assertions that depended on deliberately removed SVG titles. They now check the actual rendered icons, including exactly one header project icon. All 485 web tests pass; revised head 3f82c90f awaits required CI.

Original proposal and screenshots

Why

Four small authored-content issues from the design audit:

  1. Compact tables were centred in the prose column, so a table started 40px right of every paragraph, callout and code block.
  2. A broken image became a small grey "Image unavailable" pill, whether it was a block, inside a sentence, or inside a callout.
  3. A block formula's show-source <> toggle floated on its own line below the formula, disconnected from the block.
  4. Icons rendered a <title> (search, box-archive, xmark…), so hovering showed the raw asset name as a native tooltip.

What changed

  • Tables start at the prose edge and shrink-wrap their columns. Wide tables scroll inside the prose measure. The row and column rails still sit in the gutter outside the column.
  • Unavailable images use one element styled by placement. Alone in a paragraph (top level or in a callout), it is a quiet frame at prose width: 6rem tall, inset background, radius-md, hairline border, a muted image icon, and one line of tertiary xs text. Inside a sentence, it is an inline-code-style chip with the icon and alt text. Its accessible name is the alt text, or "Image unavailable" when there is none. Adds a Nucleo-style ImageIcon to @chopin/icons and the icon catalogue.
  • Block formulas: the toggle sits in the block's top-end corner. It uses the same btn btn-icon btn-ghost control and tooltip as code blocks. With a fine pointer it appears on hover or focus-within; it is always shown on touch, and it stays visible while the source is open. The preview's scrollport stops short of the toggle, so a long formula scrolls horizontally without passing under it.
  • Icons: LineIcon, LoaderIcon and the two planner SVG assets no longer contain <title>. Every icon is decorative and controls get their names from IconTooltip. icon-assets.test.ts now asserts there are no titles.
  • New e2e assertion in responsive-content.e2e.ts: the table and the image placeholder share the prose start edge, the inline fallback is a chip, and the formula toggle sits in the block corner.

Screenshots

Table, before (top) and after (bottom), desktop:

Table before and after

Unavailable images, before (left) and after (right), desktop. Shown at block level, in a sentence, and in a callout:

Images before and after desktop

Unavailable images, phone, before and after:

Images before and after phone

Formula, before (top: toggle below the formula) and after (bottom: corner toggle with tooltip on hover):

Formula before and after

Formula, phone (toggle always shown), before and after:

Formula phone before and after

Needs a design-contract review

bun run ci fails only on the reviewed-owner SHA-256 for the icon sources. The edits removed the title prop and <title> elements, and line.tsx gained ImageIcon. I added the ImageIcon > <LineIcon> case to the existing line.tsx exception. It is the same props-forwarding pattern as every other icon. I did not change the hashes:

File Exception file New SHA-256
packages/icons/src/icon.tsx scripts/design-contract/exceptions/dynamic-packages.json efda1a4921302c8c92c0eccb5cabc56b6a8967893246e2b5bc995f1f42bf755b
packages/icons/src/line.tsx scripts/design-contract/exceptions/dynamic-packages.json 6b76f84548559d644b3fc3c75b196265c4e9e7013ff79fe8e0a77ad8eedd5178
packages/icons/src/system.tsx scripts/design-contract/exceptions/dynamic-packages.json 81931c163dae45bdf46196e0a5c8080f81d50712b99445e3ab2cc7f88b4cba6b

These are safe because the forwarded-props data flow is unchanged. The only differences are that nothing renders a <title> child any more, and one new icon follows the existing pattern.

Testing

  • bun test packages/editor apps/web/src/icon-assets.test.ts apps/web/src/hosted.test.ts apps/web/src/chat/transcript.test.tsx: 494 pass, 0 fail
  • bun run types: pass
  • bun scripts/check-design-record.ts: pass
  • bun run ci: dprint, oxlint and tokens pass. It fails only on the design-contract hashes above.
  • Checked in the browser on a fake-GitHub server (desktop 1440×900, phone 390×844). Table rails still appear in the gutter.
  • Local e2e is suspended by the orchestrator. CI's browser job runs responsive-content, table and code.

🤖 Generated with Claude Code

@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

Review: Looks good (one polish fix suggested, nothing blocking)

Checked on a fresh build of design/authored-block-polish (fake-GitHub server, headless Chromium, desktop 1440x900 and phone 390x844) with the stress doc plus an extra doc covering images with no alt, very long alt, side-by-side inline images and images in a callout.

What works

  • Tables start at the prose edge (left 691 = paragraph left 691). A wide table is 673px wide with scrollWidth 2093 and overflow-x: auto, so it scrolls inside the measure; page scrollWidth stays 1440 and 390. Row rails sit in the gutter (x 663-677), column rails above the table. A compact table shrink-wraps flush left; the empty right side reads as intentional (like a markdown table next to full-width blocks).
  • Unavailable images: block frame is exactly prose width, 96px tall, with icon and one line of text. Long alt truncates with an ellipsis on one line, with and without alt, on phone and desktop, and inside callouts. Inline chips wrap sensibly, and two chips sit side by side. Accessible name is the alt text or "Image unavailable".
  • Formula toggle: in the block's top-right corner, opacity: 0 at rest and 1 on hover or :focus-within (fine pointer). Always visible on touch. It stays visible when source is open. It is a real button with tabindex=0, focusable, shows the focus ring and the tooltip ("Show Source"), and Enter toggles aria-expanded. The preview's side margins keep a long formula from running under it.
  • Icons: LineIcon sets aria-hidden unless aria-label or aria-labelledby is passed. No icon usage in apps/ or packages/ passes a label, so nothing relied on <title> for a name. Removing titles loses no accessible names, and it removes the raw-asset-name tooltips. The test now guards this.
  • Exception entry in dynamic-packages.json: unresolved JSX props > ImageIcon > <LineIcon> is identical to the neighbouring CloseIcon/PlusIcon entries (same shape, count 1, same forwarded-props pattern). It is justified. check-design-contract.ts fails only on "reviewed dynamic owner changed" hashes for line.tsx, icon.tsx and system.tsx, which is the allowed review-hash case. I did not touch the hashes.

Findings

  1. (polish, suggested) packages/editor/src/styles.css, new p:has(> [data-plan-src]:first-child + br...) block rule. The frame paragraph is 122px tall for a 96px frame: the trailing Lexical managed <br> still contributes a blank line (about 26px). So the space above a frame is 12px and the space below is about 38px (the callout case shows the same asymmetry before "Text with an..."). Suggested fix: in that same rule, set > br[data-lexical-managed-linebreak] { display: none } or give the frame margin-block-end: -1lh equivalent, and check the empty-paragraph placeholder is not affected.
  2. (minor, uncertain) On a wide scrolling table the column rail strip overhangs the table's right edge by about 8px (strip ends at x=1372, table at 1364), and the rails for scrolled-away columns sit at x>1440. I did not compare with main and the rails were not obviously broken, but a clip to the scrollport would be tidier. Not caused by this PR if it already behaved that way.
  3. (minor, unverified) On phone the comment button is 44px and pinned to the right edge (x 323-367), exactly where the formula toggle sits (x 338-366). I could not anchor a comment on a formula in the fixture, and formula blocks have no selectable text, so a collision looks unlikely, but it would collide if a comment anchored to a formula's first line. Worth a quick check if the Planner can anchor comments on math.
  4. (nit) .plan-image-missing chip padding uses 0.125em 0.3em and gap: 0.3em. If inline code uses a shared token for its chip padding, use that.
  5. (nit) The new e2e test covers geometry well. It does not assert the toggle is reachable by keyboard or visible on focus. Consider adding that to the same test.

No unrelated changes. Tabs, let and comment conventions are followed.

@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

Follow-ups from review, in fe4b800:

  • Space under the image frame: the paragraph's managed <br> is now hidden while an unavailable-image frame is shown. The paragraph is now exactly as tall as the frame (96px). Measured gaps at desktop: 16px above / 12px below at top level, which is the normal block rhythm (before this fix: 12px / ~38px). In the callout the frame now ends at the callout's own padding. The empty-paragraph placeholder is unaffected: the selector requires [data-plan-src]:first-child > .plan-image-missing, so a paragraph holding only a <br> never matches.
  • e2e: responsive-content now checks that the paragraph height equals the frame height. It also checks that the formula toggle has opacity 0 when the pointer is away and 1 after a programmatic focus() (focus-within).
  • Column-rail overhang: this predates the PR. rails.tsx deliberately adds pad = SEAM / 2 (8px) of slack at both ends so the outermost insert buttons aren't clipped. I measured 8px left and 8px right on a full-width table. I didn't change it.

After, desktop: the block frame, then the frame inside a callout:

Image frame after the follow-up
Callout image frame after the follow-up

CI: e2e and container pass. Validation fails only on the reviewed-owner hashes for the three icon source files, listed in the PR body.

lavaman131 added a commit that referenced this pull request Oct 6, 2026
# Conflicts:
#	apps/web/src/assets/icons/planner-stop.svg
#	apps/web/src/icon-assets.test.ts
lavaman131 added a commit that referenced this pull request Oct 6, 2026
Fixes that only exist because several open PRs now share one tree:

- Drop #290's duplicate ImageIcon and its LineIcon titles, which #287 removed.
- Remove the import #302 left unused after #276's inline code.
- Renew design-contract pins for files more than one PR edited, and record
  #290's new icons and #295's face colours as reviewed exceptions.
- Find icons by path rather than the titles #287 removed, and faces by the
  label #295 gives them.
- A tool that returns after its turn was stopped ends as failed, so #314's
  early completion keeps #272's stopped-question outcome.

Assistant-model: Claude Opus 5.5
Assistant-workflow: inline
Assistant-verification: typecheck passed: bun run types
Assistant-verification: dprint/oxlint/design checks passed: bun run ci
Assistant-verification: bun test passed: 3860 pass, 0 fail
Co-authored-by: Alex Lavaee <lavaman131@github.com>
@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

PR babysitter could not rebase this branch cleanly onto main. The branch is unchanged. Please resolve the rebase conflict locally; automation will try again after the branch changes.

@MaggieAppleton

This comment has been minimized.

@MaggieAppleton
MaggieAppleton enabled auto-merge (rebase) October 7, 2026 12:29
@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

PR babysitter could not rebase this branch cleanly onto main. The branch is unchanged. Please resolve the rebase conflict locally; automation will try again after the branch changes.

@MaggieAppleton

This comment has been minimized.

@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

PR babysitter could not rebase this branch cleanly onto main. The branch is unchanged. Please resolve the rebase conflict locally; automation will try again after the branch changes.

@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

PR babysitter could not rebase this branch cleanly onto main. The branch is unchanged. Please resolve the rebase conflict locally; automation will try again after the branch changes.

@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

CI babysitter rechecked the current failed ci run for fe4b800253a66fe910bed46d08a073830c7d6c68. The head still matches the recorded candidate, and the failure remains the reviewed design-contract hash check for packages/icons/src/icon.tsx, packages/icons/src/line.tsx, and packages/icons/src/system.tsx, while e2e and container are green.

I did not queue a commit from this runner because bun and mise are not installed here, so I could not run the required local reproduction and verification commands (bun install --frozen-lockfile, bun run fix, bun run ci). Next action for a human: on a machine with Bun 1.4.2 available, rerun those commands on this head, review those design-contract owner changes, and renew the exact exceptions only if they are approved.

babysit-head:fe4b800253a66fe910bed46d08a073830c7d6c68

Generated by PR CI fixer · gpt54 · 18.2 AIC · ⌖ 4.44 AIC · ⊞ 16.4K · ◷

MaggieAppleton and others added 2 commits October 7, 2026 20:59
… and icon titles

- Tables start at the prose edge instead of centring; wide ones scroll within
  the prose measure while the rails stay in the gutter.
- An image that fails to load becomes a quiet framed placeholder when it is
  alone in its paragraph and an inline chip inside a sentence, both labelled
  by the alt text. Adds a Nucleo-style ImageIcon.
- A block formula's show-source toggle sits in its top-end corner and is
  revealed on hover or focus (always shown on touch).
- Icons no longer render <title>, which showed the raw asset name as a
  native tooltip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… reveal

The paragraph's managed line break added ~26px below the frame. Hide it
while the frame is shown, and check in e2e that the formula toggle
appears on focus-within.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaggieAppleton
MaggieAppleton force-pushed the design/authored-block-polish branch from 5a49fa5 to 19e3979 Compare October 7, 2026 19:59
@MaggieAppleton
MaggieAppleton force-pushed the design/authored-block-polish branch from 19e3979 to 3f82c90 Compare October 7, 2026 20:11
@MaggieAppleton
MaggieAppleton merged commit bb50010 into main Oct 7, 2026
3 checks passed
@MaggieAppleton
MaggieAppleton deleted the design/authored-block-polish branch October 7, 2026 20:20
Sign up for free to 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