Repository navigation
feat(ui): clamp long text items with scroll and edge fades - #31
Merged
Merged
Conversation
Plain-text items (typically voice-transcribed) grew the card without bound. Wrap the plain-text <p> in a max-h-64 overflow-y-auto container reusing the existing scrollbar-none utility; short content renders pixel-identical (mt-2 moves to the wrapper, no padding added). Top/bottom 1.5rem gradient fades (white -> 60% white at 55% -> transparent) indicate clipped content and track scroll position in both directions: top fade only when scrollTop > 0, bottom fade only when there is hidden content below, measured on scroll and re-measured on mount and whenever item.text changes (covers content replaced after an edit-save). Tradeoffs: - Fades are siblings of the scroller inside a relative wrapper, not children of it: absolutely positioned children of a scroll container scroll away with the content, so they could never stay pinned to the visible edges. - Fade overlays use pure white while the card hover background is #fdfcfa (~1% luminance difference, imperceptible); this keeps the gradient a static utility class instead of a JS-synced background. - The bottom-edge check keeps 1px slack so fractional scrollHeight at pinch-zoom or non-integer zoom levels cannot pin the bottom fade on. - scrollTop is external DOM state, not derivable from runes, so the imperative measure-and-write in an $effect is deliberate; a ResizeObserver for font-swap-driven reflow was left out as none of the supported cases (initial, scroll, text swap) need it. Scope: plain-text branch only; the code block branch, FileBrowser, and collection headers are untouched.
Review follow-up to 59b2cad: the previous $effect only re-measured on mount, scroll, and item.text changes. Width-driven reflow — window resize, phone rotation, late webfont swap — changes overflow state without firing any of those, leaving a stale bottom fade over the last line (or a missing fade when text starts overflowing). Observe the scroller and its content with a platform ResizeObserver, measure from the observer callback, disconnect in the effect cleanup. This subsumes the item.text dependency: text swaps that change the content's size fire the observer, swaps that do not leave the overflow state identical. The sync initial measure stays so the first paint already has correct fades (ResizeObserver's first callback is async). This retracts the 'no ResizeObserver' tradeoff recorded in the previous commit body; everything else there is unchanged.
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.
What
Plain-text items (the voice-input path) can grow a card without bound. The text body now renders inside a scroll container capped at 16rem:
scrollbar-none(existing utility) keeps the scrollbar invisible; touch and wheel scrolling work natively.scrollTop > 0for the top,scrollTop + clientHeight < scrollHeightfor the bottom). Fades are siblings of the scroller so they never scroll away, and arepointer-events-none+aria-hidden.Verification
mise run checkgreen (oxfmt, oxlint, svelte-check, tsc).pnpm vitest run40/40.