refactor(text): render the annotated display view client-side - #302
Merged
HugoFara merged 2 commits intoAug 30, 2026
Merged
Conversation
This was referenced Aug 30, 2026
Two gaps in GET /texts/{id}/annotation, both found while moving the
annotated display view onto it:
- Items carried no romanization, so a client could only get one by querying
per word. Added, resolved for the whole text in a single query rather than
one lookup per term — the annotated view renders every word at once, so the
naive form would be hundreds of round trips on a normal text.
- Blank rows came back as words with empty text. Splitting the stored
annotation on newlines yields an entry for any trailing or repeated newline,
and the endpoint reported those as terms; the annotated print view has been
rendering two empty <ruby> elements per text as a result. They are now
skipped, matching the rule TextDisplayService::parseAnnotationItem() has
always applied.
/text/{id}/display was the last page still building content in PHP: it
parsed the stored annotation and echoed a <ruby> per term. It now ships a
shell and fetches GET /api/v1/texts/{id}/annotation, which the print view
already used, so display_main.php, display_header.php and display_text.php
collapse into one display_alpine.php.
The generated markup is deliberately identical to what PHP emitted —
.anntermruby for the term inside <rb>, .anntransruby2 for the translation
inside <rt>, romanization as a title attribute, and a paragraph marker
closing and reopening <p> at the language's text size with the same 1.35
then 1.3 line heights. annotation_toggle.ts drives the show/hide buttons by
querying those classes at click time, so anything else would break them
silently. Verified against both annotated texts in the dev database: same
paragraph count, same term count, same line heights, toggles still working.
Prev/next navigation stays server-rendered. It reads the request's language
filter, search query and tag selection out of the session, none of which has
an endpoint, and it is chrome rather than content.
HugoFara
force-pushed
the
refactor/client-side-annotated-display
branch
from
August 30, 2026 22:14
0eba008 to
1a8d32b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 5 of 6. Base: #301 (needs
ConfigIsland). Two commits: the endpointfix, then the conversion that depends on it.
/text/{id}/displaywas the last page still building content in PHP — it parsedthe stored annotation and echoed a
<ruby>per term. It now ships a shell andfetches
GET /api/v1/texts/{id}/annotation, the endpoint the print view alreadyused, so
display_main.php,display_header.phpanddisplay_text.phpcollapse into one
display_alpine.php.First commit: two gaps in the endpoint
per word. Added, resolved for the whole text in a single query — the
annotated view renders every word at once, so the naive form would be hundreds
of round trips on a normal text.
annotation on newlines yields an entry for any trailing or repeated newline,
and the endpoint reported those as terms. The annotated print view has been
rendering two empty
<ruby>elements per text as a result — a pre-existingbug, not one introduced here. They are now skipped, matching the rule
TextDisplayService::parseAnnotationItem()has always applied.Second commit: the conversion
The generated markup is deliberately identical to what PHP emitted —
.anntermrubyfor the term inside<rb>,.anntransruby2for the translationinside
<rt>, romanization as atitleattribute, and a paragraph markerclosing and reopening
<p>at the language's text size with the same 1.35 then1.3 line heights.
annotation_toggle.tsdrives the show/hide buttons byquerying those classes at click time, so anything else would break them
silently.
Prev/next navigation stays server-rendered. It reads the request's language
filter, search query and tag selection out of the session, none of which has an
endpoint, and it is chrome rather than content.
Verified against real data, not just tests
Both annotated texts in a live database, before and after: same paragraph count,
same term count (77 and 42), same line heights, zero empty rubies, toggles still
masking the right elements. The item counts now match
TextDisplayService::parseAnnotations()exactly, which is the old renderer'sown parser.
Stack: #298 → #299 → #300 → #301 → 5 → #6