Skip to content

Commit 50df79e

Browse files
committed
recall: baseline-anchor the inline replay glyph
TextCenter placement put the triangle ~15px low beside plain text and ~15px high beside accented text: combining accents grow that line's box and move its center, so no single nudge could fit both. Anchor the placeholder to the baseline — which accents cannot move — and re-center the ink with one measured offset. Pixel-verified <=1px against both a plain full-size word line and an accented, scaled sentence line.
1 parent eb45441 commit 50df79e

1 file changed

Lines changed: 19 additions & 2 deletions

File tree

tool/src/main/kotlin/com/dvdutch/recall/ui/NodeComposables.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Column
99
import androidx.compose.foundation.layout.Row
1010
import androidx.compose.foundation.layout.RowScope
1111
import androidx.compose.foundation.layout.fillMaxSize
12+
import androidx.compose.foundation.layout.offset
1213
import androidx.compose.foundation.layout.fillMaxWidth
1314
import androidx.compose.foundation.layout.height
1415
import androidx.compose.foundation.layout.padding
@@ -93,6 +94,15 @@ private const val CLOZE_STATE_HIDDEN = "hidden"
9394
*/
9495
internal const val AUDIO_GLYPH = "▶︎"
9596

97+
/**
98+
* Downward ink re-centering for the ▶ glyph from its baseline-anchored box, as a fraction
99+
* of its font size. The placeholder anchors to the BASELINE (not the line center) because
100+
* combining accents (e.g. Кири́лл) grow a line's box and shift its center — the baseline is
101+
* the one reference they cannot move, so one measured constant lands the glyph on the
102+
* x-height optical center of BOTH plain and accented lines (pixel-verified ≤1px on each).
103+
*/
104+
private const val AUDIO_GLYPH_INK_OFFSET_EM = 0.20f
105+
96106
/** The inlineContent id for the audio-replay glyph at track [track] within a text node. */
97107
internal fun audioInlineId(track: Int): String = "audio:$track"
98108

@@ -207,7 +217,7 @@ private fun audioInlineContent(
207217
Placeholder(
208218
width = glyphEm.em,
209219
height = glyphEm.em,
210-
placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter,
220+
placeholderVerticalAlign = PlaceholderVerticalAlign.AboveBaseline,
211221
),
212222
) {
213223
// The content fills the placeholder box (sized in em, above); the whole box is the
@@ -220,10 +230,17 @@ private fun audioInlineContent(
220230
.clickable { onPlayTrack(track) },
221231
contentAlignment = Alignment.Center,
222232
) {
233+
// Baseline-anchored box + measured downward nudge: re-centers the ▶ INK on
234+
// the leading text's x-height middle (see AUDIO_GLYPH_INK_OFFSET_EM).
235+
val glyphStyle = cardCopyStyle(LightThemeTokens.typography.copy).scaledBy(scale)
236+
val inkNudge = with(androidx.compose.ui.platform.LocalDensity.current) {
237+
(glyphStyle.fontSize.toDp()) * AUDIO_GLYPH_INK_OFFSET_EM
238+
}
223239
Text(
224240
text = AUDIO_GLYPH,
225241
color = LightThemeTokens.colors.content,
226-
style = cardCopyStyle(LightThemeTokens.typography.copy).scaledBy(scale),
242+
style = glyphStyle,
243+
modifier = Modifier.offset(y = inkNudge),
227244
)
228245
}
229246
}

0 commit comments

Comments
 (0)