Add UI that enables user to gloss tokens and add render window for ContinuousView#77
Add UI that enables user to gloss tokens and add render window for ContinuousView#77alex-rawlings-yyc wants to merge 13 commits into
Conversation
|
Note Reviews pausedUse the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR wires per-token gloss editing through TokenChip/PhraseBox/SegmentView/ContinuousView, adds external phrase focus control and windowed continuous rendering, preserves focus across mode switches, implements coordinated scrolling, and updates/extends tests to cover these behaviors. ChangesGloss editing and phrase focus
Sequence Diagram(s)sequenceDiagram
participant User
participant SegmentView
participant ContinuousView
participant TokenChip
participant Interlinearizer
User->>SegmentView: click token
SegmentView->>Interlinearizer: onSelect(ref, tokenId)
Interlinearizer->>Interlinearizer: compute activePhraseIndex
Interlinearizer->>ContinuousView: activePhraseIndex (prop)
ContinuousView->>ContinuousView: update focusPhraseIndex / window
ContinuousView->>Interlinearizer: onFocusPhraseIndexChange(focusIndex)
Interlinearizer->>SegmentView: focusedTokenId (prop)
User->>TokenChip: type gloss
TokenChip->>Interlinearizer: onGlossChange(tokenId, value)
Interlinearizer->>ContinuousView: glosses (prop)
Interlinearizer->>SegmentView: glosses (prop)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
814b41f to
38ee1e4
Compare
46af76b to
68b2942
Compare
824f214 to
45d6ad8
Compare
- Add gloss input to TokenChip (word tokens only): bordered chip now stacks surface text above an editable gloss field - Thread `glosses` (Record<string, string>) and `onGlossChange(tokenId, value)` props down through TokenChip → PhraseBox → SegmentView → ContinuousView - Introduce a phrase-window around the focused index in ContinuousView to cap rendered PhraseBoxes and reduce overhead on large books - Replace SegmentView's `onClick` with `onSelect(ref, tokenId?)` so the clicked token id propagates up to Interlinearizer - Add `activePhraseIndex` prop to ContinuousView for external phrase jumps when a segment-view token is clicked in continuous-scroll mode - Update tests to cover gloss propagation, `activePhraseIndex` jumps, and both phrase-window boundary branches
…nChip` type guard to ensure that `input` always has a handler; update docs
…, add coalescing nullish fallback for token chip gloss, extract names prop types for components
…tton - Replace the `glosses`/`onGlossChange` prop-drilling pattern with a `GlossStoreProvider` context backed by `useSyncExternalStore`, so `TokenChip` reads and writes glosses directly without intermediary props passing through `PhraseBox`, `SegmentView`, `ContinuousView`, and `Interlinearizer`. - Add a sticky "Scroll to active verse" button (using the `LocateFixed` icon) that imperatively scrolls the `aria-current` segment into view. Rename `chapterSegments` to `bookSegments` throughout.
- Extract `InertTokenChip` / `MemoizedInertTokenChip` for non-word tokens, removing the punctuation branch from `TokenChip` so it only handles words - Convert `PhraseBox` from a `<button>` to a `<label>` so clicking anywhere on the phrase focuses the first gloss input natively - Rename prop `onClick` → `onFocusPhrase` on `PhraseBox` to reflect the narrowed trigger (gloss-input focus only, not arbitrary clicks) - Update `ContinuousView` and `SegmentView` to import `MemoizedInertTokenChip` and pass `onFocusPhrase` instead of `onClick` - Update all test mocks and assertions to match the new component shapes
- `GlossStore` stored a flat string map keyed by `token.id`. `AnalysisStore` replaces it with a `TextAnalysis`-backed store: each gloss write creates a new approved `TokenAnalysis` + `TokenAnalysisLink`, the full analysis snapshot is accessible via `useAnalysis`, and `onSave` propagates changes to the caller for persistence. The store also accepts an `analysisLanguage` prop to support non-English glosses. - Token identity keys are migrated from token.id to token.ref throughout (`TokenChip`, `PhraseBox`, `SegmentView`, `ContinuousView`, `Interlinearizer`, and all corresponding tests). - Some unneeded tests removed and some adjustments to documents made
45d6ad8 to
3c7f489
Compare
72bc408 to
d113425
Compare
imnasnainaec
left a comment
There was a problem hiding this comment.
@imnasnainaec reviewed 12 files and all commit messages, and made 2 comments.
Reviewable status: 12 of 28 files reviewed, 1 unresolved discussion (waiting on alex-rawlings-yyc).
src/components/AnalysisStore.tsx line 185 at r8 (raw file):
* @param value - The new gloss string. */ const onGlossChange = useCallback(
From Devin:
src/components/AnalysisStore.tsx:R185-214
AnalysisStore creates a new TokenAnalysis on every keystroke — unbounded data growth
Each call to onGlossChange in src/components/AnalysisStore.tsx:180-207 appends a new TokenAnalysis and TokenAnalysisLink without removing or replacing the previous one. Since TokenChip.onChange fires on every keystroke (src/components/TokenChip.tsx:31), typing a 5-character gloss creates 5 approved analyses for that token. The buildApprovedGlossIndex always picks the last approved link, so behavior is correct, but the tokenAnalyses and tokenAnalysisLinks arrays grow without bound during a session. The JSDoc at line 171-173 acknowledges this as intentional ("multiple competing analyses" design), but if onSave persists to storage on every mutation, this could cause significant storage bloat over time.
src/components/component-types.ts at r8 (raw file):
⛏️ We probably want consistent organization/naming between this file and the things currently in src/types/ and src/utils/. (And I'm not implying that the latter is better.)
|
Previously, imnasnainaec (D. Ror.) wrote…
Given that |
|
Previously, alex-rawlings-yyc (Alex Rawlings) wrote…
nvm, I just realized what you meant better. I'm going to leave this as-is in the next commit for now and we can discuss what to really do about this on Discord |
…ssChange to keep stored analyses minimal for now
alex-rawlings-yyc
left a comment
There was a problem hiding this comment.
@alex-rawlings-yyc made 1 comment.
Reviewable status: 12 of 28 files reviewed, 1 unresolved discussion (waiting on alex-rawlings-yyc and imnasnainaec).
src/components/AnalysisStore.tsx line 185 at r8 (raw file):
Previously, imnasnainaec (D. Ror.) wrote…
From Devin:
src/components/AnalysisStore.tsx:R185-214
AnalysisStore creates a new TokenAnalysis on every keystroke — unbounded data growth
Each call to
onGlossChangeinsrc/components/AnalysisStore.tsx:180-207appends a newTokenAnalysisandTokenAnalysisLinkwithout removing or replacing the previous one. SinceTokenChip.onChangefires on every keystroke (src/components/TokenChip.tsx:31), typing a 5-character gloss creates 5 approved analyses for that token. ThebuildApprovedGlossIndexalways picks the last approved link, so behavior is correct, but thetokenAnalysesandtokenAnalysisLinksarrays grow without bound during a session. The JSDoc at line 171-173 acknowledges this as intentional ("multiple competing analyses" design), but ifonSavepersists to storage on every mutation, this could cause significant storage bloat over time.
This is what sent me down the rabbit hole of wiring up the suggestion engine, so I forgot to fix it again. I've fixed it in my latest commit, though note that I intentionally limited glossing to be 1:1 between token instances and analyses
…mmitted gloss differ
glosses(Record<string, string>) andonGlossChange(tokenId, value)props down through TokenChip → PhraseBox → SegmentView → ContinuousViewonClickwithonSelect(ref, tokenId?)so the clicked token id propagates up to InterlinearizeractivePhraseIndexprop to ContinuousView for external phrase jumps when a segment-view token is clicked in continuous-scroll modeactivePhraseIndexjumps, and both phrase-window boundary branchesThis change is
Summary by CodeRabbit
New Features
Improvements
Tests
Documentation