Public: anyone can read this; the crew can change it.

Design: acting on a limb uses the design system's row and dialog, and limb-* leave §5d #3188

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The limb confirm step in `src/web/pages/limb.ts` now uses the §5 dialog, and its lists use the §5 row. The page's own `.limb-confirm`, `.limb-rows` and `.limb-why`, and the `limbCss` that held their rules, are gone. Their entry also leaves `docs/DESIGN.md` §5d. `bun scripts/design-lint.ts` passes, the type check is clean, and the limb tests pass (29). This pull has no before/after looks yet, which…

shipped production is serving it deploy 84c60a0

opened this

The limb confirm step in src/web/pages/limb.ts now uses the §5 dialog, and its lists use the §5 row. The page's own .limb-confirm, .limb-rows and .limb-why, and the limbCss that held their rules, are gone. Their entry also leaves docs/DESIGN.md §5d. bun scripts/design-lint.ts passes, the type check is clean, and the limb tests pass (29). This pull has no before/after looks yet, which the issue asks for (see below).

What moved

  • Confirm step: it is now a <form class="dialog"> sitting inline in the preview page, with the usual dialog head, body and foot.

- The head is the action ("Defer this limb?"). - The body holds the close reason as field() and the resume pillar as selectField(). Both keep the ids limb-reason and limb-pillar. - The foot holds Back and the action button. - This page is the "real page behind" the dialog, so it needs no script. Below 720px it takes the dialog's sheet shape.

  • "What is written" and the receipt: each is a listCard of row()s. The title links to the issue, and the meta line reads #N · before → after. The meta also carries the reason when there is one, and has a title so the full text can still be read when the line is cut short. A refused or failed row now shows an attn badge with the outcome instead of .limb-why. It is no longer greyed out.
  • src/web/ui.ts: field() gained an optional maxlength, so the reason keeps its 300-character limit. Nothing else renders differently, because it is only output when set.

Test change (test/limbs.test.ts)

  • One assertion changed because the markup changed, not because the old test was wrong. It checked the old <a href=…>One interface</a>, and now matches the .row / .row-title markup.
  • New assertions check that the confirm is a <form method="post" action="…/limb" class="dialog"> with its titled head, that no class="limb- is left, and that the close reason is a required field with maxlength="300".
  • The existing proofs are unchanged: nothing is written by the preview, a reader gets nothing to confirm, a POST from another origin is a 403, a close without a reason goes back to the preview, and undo works once.

Not done

  • I left the .ms-rows lists (taken, kept, order, ready) alone. They belong to milestones.ts and are outside this issue.
  • The page does not open as a modal over the milestone with JS. That would be new behaviour.
  • Looks: I couldn't take the before/after pictures the issue asks for (desktop and 360px, light and dark). The forge takes its pictures signed out, and this page needs a signed-in admin, so it can't go in app.looks. Someone who can write the app needs to attach them to the pull.

To try it: sign in as an admin and open a limb from a milestone, for example /alice/engine/milestones/5/limb?action=defer (the test repo), or action=close for the reason field and action=resume for the pillar picker. Then confirm and look at the receipt at …/limb/<op>.

🤖 Generated with Claude Code

Closes #3185

commented

The limb confirm step in src/web/pages/limb.ts now uses the §5 dialog, and its lists use the §5 row. The page's own .limb-confirm, .limb-rows and .limb-why, and the limbCss that held their rules, are gone. Their entry also leaves docs/DESIGN.md §5d. bun scripts/design-lint.ts passes, the type check is clean, and the limb tests pass (29). This pull has no before/after looks yet, which the issue asks for (see below).

What moved

  • Confirm step: it is now a <form class="dialog"> sitting inline in the preview page, with the usual dialog head, body and foot.

- The head is the action ("Defer this limb?"). - The body holds the close reason as field() and the resume pillar as selectField(). Both keep the ids limb-reason and limb-pillar. - The foot holds Back and the action button. - This page is the "real page behind" the dialog, so it needs no script. Below 720px it takes the dialog's sheet shape.

  • "What is written" and the receipt: each is a listCard of row()s. The title links to the issue, and the meta line reads #N · before → after. The meta also carries the reason when there is one, and has a title so the full text can still be read when the line is cut short. A refused or failed row now shows an attn badge with the outcome instead of .limb-why. It is no longer greyed out.
  • src/web/ui.ts: field() gained an optional maxlength, so the reason keeps its 300-character limit. Nothing else renders differently, because it is only output when set.

Test change (test/limbs.test.ts)

  • One assertion changed because the markup changed, not because the old test was wrong. It checked the old <a href=…>One interface</a>, and now matches the .row / .row-title markup.
  • New assertions check that the confirm is a <form method="post" action="…/limb" class="dialog"> with its titled head, that no class="limb- is left, and that the close reason is a required field with maxlength="300".
  • The existing proofs are unchanged: nothing is written by the preview, a reader gets nothing to confirm, a POST from another origin is a 403, a close without a reason goes back to the preview, and undo works once.

Not done

  • I left the .ms-rows lists (taken, kept, order, ready) alone. They belong to milestones.ts and are outside this issue.
  • The page does not open as a modal over the milestone with JS. That would be new behaviour.
  • Looks: I couldn't take the before/after pictures the issue asks for (desktop and 360px, light and dark). The forge takes its pictures signed out, and this page needs a signed-in admin, so it can't go in app.looks. Someone who can write the app needs to attach them to the pull.

To try it: sign in as an admin and open a limb from a milestone, for example /alice/engine/milestones/5/limb?action=defer (the test repo), or action=close for the reason field and action=resume for the pillar picker. Then confirm and look at the receipt at …/limb/<op>.

🤖 Generated with Claude Code

Approved

Reads as the design system: the confirm is the §5 dialog (real form, POST, works with JS off, labelled by its h2), the rows are §5 rows in a listCard, the reason and pillar are field()/selectField() with their ids kept, and limb-* plus the §5d entry are gone. Tests assert the new markup and would fail without it. I could not open the preview or the screenshots from my sandbox, so the visual judgement is from the source and CSS only.

Two things I would do next:

  1. Attach the before/after looks the issue asks for (360px and desktop, light and dark). On the phone, the inline dialog gets the sheet shape from the 719px rule, which rounds only the top corners while sitting in the page flow. Check it by eye and consider data-side or a full radius for the inline case.
  2. The row meta repeats its text in a title attribute, and a refused row now relies on a badge instead of the muted colour. Confirm the meta truncation is acceptable on 360px and that the badge text is read with the row title by a screen reader.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs