Submission draft editor: keep variable link in preview after fill + click-field-highlights-occurrences-in-preview #106
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
m's report (2026-05-25 16:22)
Two bidirectional improvements over #92 (already shipped)
Concern A — link persists after fill
Current behavior: when a variable is unfilled (template literal
{{project.case_number}}shows in preview), clicking it jumps to the sidebar field. After the user fills the field, the preview renders the substituted value but the click-to-jump linkage disappears.Fix: render the
<span class="draft-var" data-var="…">wrapper around BOTH the unfilled placeholder AND the filled substituted value. Samedata-varattribute, same click handler. The user can click ANY rendered variable (filled or not) and jump to its field.Edge: the
.draft-varstyling on a filled variable should be subtle — current state-of-the-art is a dotted underline on hover or a small badge on right. Coder picks; default to dotted-underline-on-hover so the prose stays clean when not interacting.Concern B — click-into-field highlights occurrences in preview
Reverse direction: when the user focuses a sidebar input (say
project.case_number), the preview should highlight every<span class="draft-var" data-var="project.case_number">…</span>occurrence with a brief lime flash (or sticky highlight while the field stays focused, returning to normal on blur).Use the same
data-varmapping. Onfocusinof a[data-field-key]input, find matching.draft-varspans and add.draft-var--activeclass; onfocusout, remove.Files most likely touched
internal/services/submission_render.go(or wherever the preview HTML is generated) — wrap filled values in the same<span class="draft-var">as unfilled (currently only unfilled get wrapped, judging by m's report)frontend/src/client/submission-draft.ts— bidirectional event handlers (preview→field click + field→preview focus highlight)frontend/src/styles/global.css—.draft-varhover/active styling, dotted underlineHard rules
<span class="draft-var">is preview-HTML-only.go build ./... && go test ./internal/... && cd frontend && bun run buildclean.mai/<worker>/draft-editor-bidirectional-link.Out of scope
Reporting
mai report completedwith branch + SHAs + UX path: A) type a value into a sidebar field → confirm the filled substituted value in the preview stays clickable + still jumps back to its field; B) click into any sidebar field → confirm every matching variable in the preview gets a highlight, blur → highlight clears.Branch
mai/hermes/gitster-draft-editor— commitd4df81e.What landed
Concern A — link persists after fill
Audited the Go renderer:
substituteInTextNodes/substituteAcrossRunsalready pass both filled and missing values throughhtmlPreviewWrapper, so the<span class="draft-var" data-var="…">wrapping was present for every substituted placeholder before this slice (verified by existingTestRenderHTML_ExtractsParagraphsAndFormattingandTestRenderHTML_WrapsMissingMarker).What looked broken in your test was a visibility problem, not a markup problem: the always-on
rgba(198, 244, 28, 0.12)tint was imperceptible against the serif preview prose, so a filled value read as plain text and the click affordance felt gone.Fix:
TestRenderHTML_WrapsOverriddenValueSameAsResolvedpins that an override (project.case_number = "UPC_CFI_42/2026") and a resolved value (firm.name = "HLC") both end up wrapped in matchingdraft-varspans. Future refactors can't drop the wrap on either path without the test screaming.--has-inputspan, layered a dotted underline + brighter lime tint so the affordance reveals itself. Missing markers carry their own[KEIN WERT: …]gap text and don't need extra visual highlight.Concern B — sidebar-field-focus → preview-occurrence highlight (new)
Reverse direction of the click-to-jump from #92.
focusinon any.submission-draft-var-inputapplies.draft-var--activeto every matching span in the preview;focusout(or focus shift via Tab) clears them. Sticky-while-focused — the user can scan "where does this variable land?" while typing.New CSS
.draft-var--activeuses a brighter lime + box-shadow ring so all occurrences pop at once.Autosave-survival wiring
Both directions had to be re-applied at the end of
paintVariablesANDpaintPreviewbecause:paintVariablesruns after autosave and re-creates every input viainnerHTML, so thefocusinlistener attached to the old input is gone;restoreVarFocusputs focus back programmatically without firingfocusinagain. We re-apply explicitly to bridge.paintPreviewblows away the preview HTML on every autosave, so any prior--activeclass is gone. Re-applied based on the currently-focused sidebar input.Files changed
internal/services/submission_merge_test.go— new regression testfrontend/src/client/submission-draft.ts— focus handlers + re-apply on repaintfrontend/src/styles/global.css—.draft-varrewrite,.draft-var--activeUX verification path
A — link persists after fill:
project.case_number).B — click into field highlights occurrences:
firm.name).firm.nameoccurrence in the preview lights up with the brighter lime + ring (sticky while the field stays focused).Hard rules verified
.docxexport unchanged (Renderpassesnilwrap; covered by existingTestRender_DocxOutputUnchangedByPreviewWrap).go build ./...+go test ./internal/...+bun run buildall clean.