Skip to content

refactor(text): render the annotated display view client-side - #302

Merged
HugoFara merged 2 commits into
refactor/config-islandsfrom
refactor/client-side-annotated-display
Aug 30, 2026
Merged

refactor(text): render the annotated display view client-side#302
HugoFara merged 2 commits into
refactor/config-islandsfrom
refactor/client-side-annotated-display

Conversation

@HugoFara

Copy link
Copy Markdown
Owner

Stack 5 of 6. Base: #301 (needs ConfigIsland). Two commits: the endpoint
fix, then the conversion that depends on it.

/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, the endpoint the print view already
used, so display_main.php, display_header.php and display_text.php
collapse into one display_alpine.php.

First commit: two gaps in the endpoint

  • 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 — 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
    — a pre-existing
    bug, 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 —
.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.

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's
own parser.

Stack: #298#299#300#3015#6

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
HugoFara force-pushed the refactor/client-side-annotated-display branch from 0eba008 to 1a8d32b Compare August 30, 2026 22:14
@HugoFara
HugoFara merged commit 27ac193 into develop Aug 30, 2026
28 checks passed
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