Skip to content

Port the new UI design, and fix the load path it exposed - #5

Merged
IPerception merged 2 commits into
mainfrom
feat/ui-redesign
Aug 16, 2026
Merged

Port the new UI design, and fix the load path it exposed#5
IPerception merged 2 commits into
mainfrom
feat/ui-redesign

Conversation

@IPerception

Copy link
Copy Markdown
Owner

Restyles the browser app to the design generated in Claude, while keeping every
feature added since that design was made. Both halves were the requirement: the
design was built from an early version and covers roughly half of what the app
now does.

Ships as v1.1.0.

Design

  • 24 themed tokens across all four theme blocks. Light and dark are both the
    design's own values, recovered from the LIGHT/DARK maps in its script
    block — those tokens are applied at runtime and never written as CSS, which is
    why they first appeared undefined. The design re-tints toward blue on the
    way to dark rather than desaturating; deriving dark by preserving the light
    theme's neutral hue produced a flat charcoal that read visibly dull.
  • The three identity hues the design has no colour for (shift, swap, deid)
    are generated at the measured lightness and chroma of its accent, per
    theme, so they sit at the same visual weight. New -2 variants take chip text
    on its own wash from ~3.8:1 to ~9:1 — AA rather than not.
  • Barlow Condensed embedded, subset to the glyphs this app renders: 20.6 KB
    for both weights against 44 KB unsubsetted. web/embed-font.py is the tool.
    SIL OFL 1.1, no Reserved Font Name; the copyright, licence and URL ride in the
    font's own name table, because the single HTML file travels detached from this
    repo and a repo-only OFL.txt cannot discharge that.
  • Every border-radius removed; the masthead moved into a full-width header
    carrying a mono readout strip; numbered rail stations; an accent rule under
    the selected tab; corner ticks on the four panels that do not repeat; and the
    graph-paper ground on the empty state only.
  • Data rows get their own size lever, --step-row, separate from the chrome
    scale — Document, Tree, Claims and Checks read at 14px.

The grid ground is deliberately not on .stage. ROW_H is 24 and
TREE_ROW_H is 28 against a 28px grid: on the Tree that rules every row, and on
the Document the two pitches beat with a 168px period that crawls as a
virtualized list scrolls.

Fixes

  • Loading a file left the previous document's view state in place.
    selectTab paints the row list before renderDocument rebuilds it, so a
    stale visible was indexed against the new document's segments and threw out
    of renderRow — aborting loadFile before renderDocument and
    updateReadouts. The file name changed, nothing else did, and no error
    reached the screen. The tree half of this reset always existed, which is why
    the Tree tab never had the bug.
  • windowRange had no upper clamp, which is what made that silent: it
    returned first: 8325 against a total of 31, and the slice came back empty.
  • The Document filter scrolled out of reach while the outline stayed pinned, and
    selecting a claim welded the list to the tab strip.
  • .claims-scroll and the outline height cap were hand-tallied constants
    describing chrome that had changed height. Both now measure it.

Tests

  • New render.mjs, a ninth suite. It drives the app against a thin DOM shim,
    including the load-over-load sequence the bug above lived in. Every other suite
    tests a pure function, and this class of fault was invisible to all of them and
    to every static check in lint.mjs. Verified by removing the state reset and
    watching the assertion go red.
  • Two assertions that wrote down a number which was really a consequence of
    another number now derive it instead.
  • lint.mjs rule 8 rewritten: the mask and theme toggles are asserted to sit in
    the page header rather than outside .rail-body, which no longer exists. The
    bug it guards has happened once, so it is re-expressed, not dropped.

Verification

node web/tests/all.mjs — all 9 suites green. python -m unittest — 11 tests,
green. The app is 290 KB, up from 256 KB; 20.6 KB of that is the embedded font.
Checked before staging that no design source material is committed: the
generated web/fonts/face.css is gitignored, and docs/notes/ — the artifact,
its 44 unpacked assets and 39 source .woff2 files — stays out.

Merging deploys to the live Pages demo, which tracks main rather than the tag.

🤖 Generated with Claude Code

IPerception and others added 2 commits August 16, 2026 19:52
Restyles the browser app to the design generated in Claude, keeping every
feature added since that design was made. Both halves were the requirement:
the design covers roughly half of what the app now does.

Design

- 24 themed tokens across all four theme blocks. Light and dark are both the
  design's own values, recovered from the LIGHT/DARK maps in its script block.
  Those tokens are applied at runtime and never written as CSS, which is why
  they first looked undefined. The design re-tints toward blue on the way to
  dark rather than desaturating; copying the light theme's neutral hue gave a
  flat charcoal that read dull.
- The three identity hues the design has no colour for (shift, swap, deid) are
  generated at the measured lightness and chroma of its accent, per theme, so
  they sit at the same visual weight. New -2 variants take chip text on its own
  wash from about 3.8:1 to about 9:1, which is AA rather than not.
- Barlow Condensed embedded, subset to the glyphs this app renders: 20.6 KB for
  both weights against 44 KB unsubsetted. web/embed-font.py is the tool. It is
  SIL OFL 1.1 with no Reserved Font Name, and the notices ride in the font's
  own name table because the single HTML file travels detached from this repo.
- Every border-radius removed, the masthead moved into a full-width header with
  a mono readout strip, numbered rail stations, an accent rule under the
  selected tab, corner ticks on the four panels that do not repeat, and the
  graph-paper ground on the empty state only.
- Data rows get their own size lever, --step-row, separate from the chrome
  scale: the Document list, the Tree, Claims and Checks read at 14px.

Fixes

- Loading a file left the previous document's view state in place. selectTab
  paints the row list before renderDocument rebuilds it, so a stale `visible`
  was indexed against the new document's segments and threw out of renderRow,
  aborting loadFile before renderDocument and updateReadouts. The file name
  changed, nothing else did, and no error reached the screen. The tree half of
  this reset always existed, which is why the Tree tab never had the bug.
- windowRange had no upper clamp, which is what made that silent: it returned
  first 8325 against a total of 31, and the slice came back empty.
- The Document filter scrolled out of reach while the outline stayed pinned,
  and selecting a claim welded the list to the tab strip.
- .claims-scroll and the outline height cap were hand-tallied constants
  describing chrome that had changed height. Both now measure it.

Tests

- New render.mjs, a ninth suite: it drives the app against a thin DOM shim,
  including the load-over-load sequence the bug above lived in. Every other
  suite tests a pure function, and this class of fault was invisible to all of
  them and to lint.
- Two assertions that wrote down a number which was really a consequence of
  another number now derive it instead.
- lint rule 8 rewritten: the mask and theme toggles are asserted to sit in the
  page header rather than outside .rail-body, which no longer exists. The bug
  it guards has happened once, so it is re-expressed, not dropped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Minor rather than major: the redesign was explicitly required to retain every
feature, so nothing was removed or broken, and the app gained the header
readout strip and its Mode reading. A 2.0.0 would signal a break to anyone
reading the tag, and there is not one.

The rail footer string is the single source of truth. release.mjs derives both
the tag and the asset filename from it (v1.1.0, EDIWorkbench-v1.1.0.html), and
lint rule 9 pins its shape; the README links /releases/latest rather than a
pinned tag, so nothing else needed editing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@IPerception
IPerception merged commit 7e404ce into main Aug 16, 2026
1 check passed
@IPerception
IPerception deleted the feat/ui-redesign branch August 16, 2026 23:57
IPerception added a commit that referenced this pull request Aug 21, 2026
* chore: tidy the source-interchange copy

Uppercase the drop-zone label through text-transform rather than literal
caps, so case stays in the stylesheet like the app's other uppercase runs.
Tracked at .06em to sit alongside .card-title, the only other large-size
uppercase in the UI.

Rename the sample link from "Use sample" to "Load a sample".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: retake the README screenshots on the v1.1.0 UI

The four screenshots still showed the pre-redesign interface: none of them
had the new masthead or the readout strip. Retaken against the same sample
files so the existing alt text still describes what is on screen.

Two things changed beyond the styling:

- The Claims table was clipped on the right in the old capture, cutting off
  the claim total column. It now fits, so the alt text gains that column.
- The old Tree capture reported cob_loops.edi as 51 segments / 1.3 KB. The
  file is 44 segments / 1,244 bytes and has never been edited; those were
  the figures for patient_and_cob.edi, loaded before it. The readout went
  stale on load and the filename did not. Fixed by the load path work in
  #5, and the new capture reads correctly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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