Clamp Discover text boxes and preserve recovery button height
All checks were successful
review/design-claude B1-B3 re-measured by firstmate from the lane measurement file against the locked numbers (all within 2 px); delta is the three scoped fixes plus an additive main merge; N1/N2 3-4 px offsets remain as listed follow-ups

This commit is contained in:
justinzeus 2026-11-05 20:22:47 +01:00
parent bfd4002dd1
commit 130697c2eb
5 changed files with 56 additions and 7 deletions

View file

@ -54,8 +54,10 @@ fun DiscoverOverlay(state: DiscoverState) {
}
}
is DiscoverOverlayState.Restore -> {
Text(overlay.title.title, color = C.fg, style = DiscoverType.sheetTitle)
Text("Hidden from ${state.shell.person.name}’s picks.", color = C.muted, style = DiscoverType.body)
Text(overlay.title.title, Modifier.discoverLineBox(DiscoverType.sheetTitle), color = C.fg, style = DiscoverType.sheetTitle)
Text("Hidden from ${state.shell.person.name}’s picks.",
Modifier.offset(y = D.sheetSubTop).padding(bottom = D.sheetSubGap + D.sheetSubTop).discoverLineBox(DiscoverType.body),
color = C.muted, style = DiscoverType.body)
Row(Modifier.padding(top = D.sheetButtonTop), horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) {
DiscoverButton("Show again", overlay.focus == 0) { state.restore(overlay.title) }
DiscoverButton("Back", overlay.focus == 1, primary = false) { state.overlay = null }

View file

@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape
@ -125,7 +126,7 @@ private fun DiscoverHero(state: DiscoverState) {
Text(if (state.snapshot.status == DiscoverStatus.Ready) "For you" else "Trending", color = C.accentText, style = DiscoverType.label)
}
Spacer(Modifier.height(D.heroKickerGap))
Text(title.title, Modifier.width(L.heroCopyWidth), color = C.fg, style = DiscoverType.hero, maxLines = 2, overflow = TextOverflow.Ellipsis)
Text(title.title, Modifier.width(L.heroCopyWidth).testTag("discover-hero-title-box").discoverLineBox(DiscoverType.hero), color = C.fg, style = DiscoverType.hero, maxLines = 2, overflow = TextOverflow.Ellipsis)
Spacer(Modifier.height(D.heroTitleGap))
Row(Modifier.height(D.heroFactsHeight), horizontalArrangement = Arrangement.spacedBy(D.heroFactsGap), verticalAlignment = Alignment.CenterVertically) {
Text("${title.typeWord}${title.year?.let { " · $it" }.orEmpty()}", color = C.muted, style = DiscoverType.body)
@ -166,7 +167,7 @@ private fun DiscoverChips(state: DiscoverState) {
private fun DiscoverStatePanel(state: DiscoverState) {
val signIn = state.snapshot.status == DiscoverStatus.NeedsSignIn
Box(Modifier.fillMaxWidth().height(L.row_state)) {
Column(Modifier.padding(start = L.safeSide, top = D.stateTop).width(L.stateWidth)
Column(Modifier.padding(start = L.safeSide, top = D.stateTop).wrapContentHeight(Alignment.Top, unbounded = true).width(L.stateWidth)
.background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.panel))
.border(WolfskinTokens.Library.borderWidth, C.border, RoundedCornerShape(WolfskinTokens.Radius.panel))
.padding(WolfskinTokens.Library.borderWidth).padding(D.statePaddingX, D.statePaddingY)) {

View file

@ -1,6 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
package org.justinvisser.wolfskin.design
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.FirstBaseline
import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.layout.layout
import androidx.compose.ui.text.TextStyle
import kotlin.math.roundToInt
import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.LineHeightStyle
@ -22,3 +28,14 @@ internal object DiscoverType {
val entry = WolfskinTokens.Discover.entryText.copy(lineHeightStyle = lineBox, platformStyle = platform)
val ratings = WolfskinTokens.Type.ratingPlate.copy(fontFeatureSettings = "tnum", lineHeightStyle = lineBox, platformStyle = platform)
}
/** Paragraph overflow must not expand the CSS block height. */
internal fun Modifier.discoverLineBox(style: TextStyle): Modifier = layout { measurable, constraints ->
val paragraph = measurable.measure(constraints)
val lineHeight = style.lineHeight.toPx()
val lines = ((paragraph[LastBaseline] - paragraph[FirstBaseline]) / lineHeight).roundToInt() + 1
val height = (lines * lineHeight).roundToInt().coerceIn(constraints.minHeight, constraints.maxHeight)
layout(paragraph.width, height) {
paragraph.placeRelative(0, (height - paragraph.height) / 2)
}
}