Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-29 13:23:30 +03:00
parent 514e142989
commit fb96f3651f
259 changed files with 12276 additions and 40 deletions

View file

@ -12,6 +12,7 @@ import com.tangem.core.ui.ds2.loader.TangemLoaderSize
import com.tangem.core.ui.ds2.row.TangemRowContentLead
import com.tangem.core.ui.ds2.row.TangemRowVerticalAlignment
import com.tangem.core.ui.ds2.shimmers.TextShimmerStyle
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
internal sealed interface StoryBookPage
@ -228,6 +229,68 @@ internal data class TangemFadeStory(
val onBlurToggle: () -> Unit,
) : DsStoryBookPage
@Suppress("BooleanPropertyNaming")
internal data class TangemTopNavigationStory(
val contentAlign: TangemTopNavigation.ContentAlign,
val background: Background,
val contentMode: ContentMode,
val hasBack: Boolean,
val hasSubtitle: Boolean,
val longTitle: Boolean,
val endButton: EndButton,
val endGroup: EndGroup,
val useStatusBarInsets: Boolean,
val isBlurEnabled: Boolean,
val onContentAlignChange: (TangemTopNavigation.ContentAlign) -> Unit,
val onBackgroundChange: (Background) -> Unit,
val onContentModeChange: (ContentMode) -> Unit,
val onBackToggle: () -> Unit,
val onSubtitleToggle: () -> Unit,
val onLongTitleToggle: () -> Unit,
val onEndButtonChange: (EndButton) -> Unit,
val onEndGroupChange: (EndGroup) -> Unit,
val onStatusBarInsetsToggle: () -> Unit,
val onBlurToggle: () -> Unit,
) : DsStoryBookPage {
/**
* What goes inside the center `contentColumn` slot.
*
* - [Plain] basic Title / Subtitle text, drives the `hasSubtitle` + `longTitle` toggles.
* - [Rich] `AnnotatedString` with multi-color spans, an inline swap emoji, and emoji-only
* second line. Demonstrates that the slot accepts arbitrary composables, not just plain text.
*/
enum class ContentMode(val label: String) {
Plain("plain"),
Rich("rich"),
}
/** Backdrop the navigation preview sits on, to verify haze/blur behavior. */
enum class Background(val label: String) {
Rainbow("rainbow"),
BgPrimary("bg.primary"),
BgSecondary("bg.secondary"),
BgBrand("bg.brand"),
BgInverse("bg.inverse"),
}
/** Trailing slot variant — None / Close / Loader / Custom pill ("How it works?"). */
enum class EndButton(val label: String) {
None("none"),
Close("close"),
Loader("loader"),
HowItWorks("How it works?"),
}
/** Secondary-actions pill: 0..3 icon buttons. */
enum class EndGroup(val label: String) {
None("0"),
One("1"),
Two("2"),
Three("3"),
}
}
internal data class TangemBadgeV2Story(
val variant: TangemBadge.Variant,
val status: TangemBadge.Status,

View file

@ -21,6 +21,7 @@ import com.tangem.feature.tester.presentation.storybook.page.ds.fade.tangemFadeS
import com.tangem.feature.tester.presentation.storybook.page.ds.loader.tangemLoaderStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.row.tangemRowStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.shimmer.tangemShimmerStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.topnavigation.tangemTopNavigationStoryFactory
private data class DsStoryItem(val title: String, val factory: StoryPageFactory)
@ -31,6 +32,7 @@ private fun buildDsStories() = listOf(
DsStoryItem(title = "📋 TangemRow", factory = tangemRowStoryFactory),
DsStoryItem(title = "✨ TangemShimmer", factory = tangemShimmerStoryFactory),
DsStoryItem(title = "🌫️ TangemFade", factory = tangemFadeStoryFactory),
DsStoryItem(title = "🧭 TangemTopNavigation", factory = tangemTopNavigationStoryFactory),
)
@Composable

View file

@ -0,0 +1,54 @@
package com.tangem.feature.tester.presentation.storybook.page.ds.topnavigation
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
import com.tangem.feature.tester.presentation.storybook.entity.TangemTopNavigationStory
import com.tangem.feature.tester.presentation.storybook.viewmodel.StateUpdater
import com.tangem.feature.tester.presentation.storybook.viewmodel.storyPageFactory
internal fun StateUpdater<TangemTopNavigationStory>.build(): TangemTopNavigationStory {
return TangemTopNavigationStory(
contentAlign = TangemTopNavigation.ContentAlign.Start,
background = TangemTopNavigationStory.Background.Rainbow,
contentMode = TangemTopNavigationStory.ContentMode.Plain,
hasBack = true,
hasSubtitle = true,
longTitle = false,
endButton = TangemTopNavigationStory.EndButton.Close,
endGroup = TangemTopNavigationStory.EndGroup.None,
useStatusBarInsets = true,
isBlurEnabled = true,
onContentAlignChange = { align ->
updateStory { it.copy(contentAlign = align) }
},
onBackgroundChange = { background ->
updateStory { it.copy(background = background) }
},
onContentModeChange = { mode ->
updateStory { it.copy(contentMode = mode) }
},
onBackToggle = {
updateStory { it.copy(hasBack = !it.hasBack) }
},
onSubtitleToggle = {
updateStory { it.copy(hasSubtitle = !it.hasSubtitle) }
},
onLongTitleToggle = {
updateStory { it.copy(longTitle = !it.longTitle) }
},
onEndButtonChange = { endButton ->
updateStory { it.copy(endButton = endButton) }
},
onEndGroupChange = { endGroup ->
updateStory { it.copy(endGroup = endGroup) }
},
onStatusBarInsetsToggle = {
updateStory { it.copy(useStatusBarInsets = !it.useStatusBarInsets) }
},
onBlurToggle = {
updateStory { it.copy(isBlurEnabled = !it.isBlurEnabled) }
},
)
}
internal val tangemTopNavigationStoryFactory
get() = storyPageFactory(StateUpdater<TangemTopNavigationStory>::build)

View file

@ -0,0 +1,523 @@
@file:Suppress("MagicNumber")
package com.tangem.feature.tester.presentation.storybook.page.ds.topnavigation
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.tangem.core.ui.components.haze.hazeSourceTangem
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds2.button.Back
import com.tangem.core.ui.ds2.button.Close
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.topnavigation.TangemNavigationText
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
import com.tangem.core.ui.extensions.rememberLastNonNull
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.LocalHazeState
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_arrow_swap_horizontal_20
import com.tangem.core.ui.res.generated.icons.ic_scan_20
import com.tangem.core.ui.res.generated.icons.ic_sign_usd_20
import com.tangem.feature.tester.presentation.storybook.entity.TangemTopNavigationStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemTopNavigationStory.Background
import com.tangem.feature.tester.presentation.storybook.entity.TangemTopNavigationStory.ContentMode
import com.tangem.feature.tester.presentation.storybook.entity.TangemTopNavigationStory.EndButton
import com.tangem.feature.tester.presentation.storybook.entity.TangemTopNavigationStory.EndGroup
private const val SHORT_TITLE = "Title"
private const val LONG_TITLE = "Very long top navigation title that should ellipsize"
private const val SUBTITLE = "Subtitle"
private const val PREVIEW_HEIGHT_DP = 220
// Match the production TangemTopNavigation's spring stiffness so the story animates identically.
private val SlotAlphaSpec = spring<Float>(stiffness = Spring.StiffnessMediumLow)
private val SlotSizeSpec = spring<androidx.compose.ui.unit.IntSize>(stiffness = Spring.StiffnessMediumLow)
private val TitleEnterTransition = fadeIn(animationSpec = SlotAlphaSpec)
private val TitleExitTransition = fadeOut(animationSpec = SlotAlphaSpec)
private val SubtitleEnterTransition =
fadeIn(animationSpec = SlotAlphaSpec) + expandVertically(animationSpec = SlotSizeSpec)
private val SubtitleExitTransition =
fadeOut(animationSpec = SlotAlphaSpec) + shrinkVertically(animationSpec = SlotSizeSpec)
@Composable
internal fun TangemTopNavigationStory(state: TangemTopNavigationStory, modifier: Modifier = Modifier) {
val hazeState = LocalHazeState.current
DisposableEffect(state.isBlurEnabled) {
val wasBlurEnabled = hazeState.blurEnabled
hazeState.blurEnabled = state.isBlurEnabled
onDispose { hazeState.blurEnabled = wasBlurEnabled }
}
// Make the system status bar transparent for the lifetime of this story so the preview backdrop
// visually merges with the system clock/icons area — same as a real edge-to-edge screen.
// TesterActivity reapplies its solid bar color on its next recomposition (on exit).
val systemUiController = rememberSystemUiController()
DisposableEffect(systemUiController) {
systemUiController.setStatusBarColor(color = Color.Transparent, darkIcons = false)
onDispose { /* TesterActivity reapplies its color on next recomposition */ }
}
// TesterActivity wraps its NavHost in `Modifier.systemBarsPadding()`, which pushes this story
// down below the status bar. To still let the preview cover the status bar, we shift it up by
// the real status bar height and grow its height by the same amount.
val statusBarDp = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
Box(
modifier = modifier
.fillMaxSize()
.background(TangemTheme.colors.background.primary),
) {
ComponentPreview(
state = state,
statusBarDp = statusBarDp,
modifier = Modifier.align(Alignment.TopCenter),
)
Column(
modifier = Modifier
.padding(top = PREVIEW_HEIGHT_DP.dp + 16.dp)
.verticalScroll(rememberScrollState())
.padding(bottom = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
ContentAlignSelector(selected = state.contentAlign, onSelect = state.onContentAlignChange)
ContentModeSelector(selected = state.contentMode, onSelect = state.onContentModeChange)
EndButtonSelector(selected = state.endButton, onSelect = state.onEndButtonChange)
EndGroupSelector(selected = state.endGroup, onSelect = state.onEndGroupChange)
BackgroundSelector(selected = state.background, onSelect = state.onBackgroundChange)
Toggles(state = state)
}
}
}
@Composable
private fun ComponentPreview(state: TangemTopNavigationStory, statusBarDp: Dp, modifier: Modifier = Modifier) {
// The preview Box is grown by `statusBarDp` and shifted up by the same amount so its backdrop
// bleeds into (now transparent) system status bar area. The top navigation itself uses a
// matching `WindowInsets(top = statusBarDp)` so its content clears the system clock/icons,
// exactly like in a real edge-to-edge screen.
Box(
modifier = modifier
.fillMaxWidth()
.height(PREVIEW_HEIGHT_DP.dp + statusBarDp)
.offset(y = -statusBarDp),
) {
PreviewBackground(
background = state.background,
modifier = Modifier
.fillMaxSize()
.hazeSourceTangem(zIndex = 0f),
)
TangemTopNavigation(
// The bar's outer Box (and its 96dp top fade) needs to reach the very top of the
// preview, while only the inner row sits below the status bar. So we DON'T add outer
// padding — instead we push the row down via `windowInsets`.
//
// Catch: TesterActivity wraps the NavHost in `Modifier.systemBarsPadding()`, which
// marks the system bars insets as consumed for descendants. The bar's internal
// `windowInsetsPadding(windowInsets)` subtracts that consumption (`statusBarDp`)
// from whatever we pass. To still get an effective `statusBarDp` of row padding, we
// pre-compensate by passing `2 * statusBarDp` here.
modifier = Modifier.align(Alignment.TopCenter),
contentAlign = state.contentAlign,
windowInsets = if (state.useStatusBarInsets) WindowInsets(top = statusBarDp * 2) else WindowInsets(0),
startButton = if (state.hasBack) {
{ TangemButton.Back(onClick = {}) }
} else {
null
},
endButtonsGroup = endGroupContent(state.endGroup),
endButton = endButtonContent(state.endButton),
contentColumn = {
when (state.contentMode) {
ContentMode.Plain -> PlainContent(state)
ContentMode.Rich -> RichContent()
}
},
)
}
}
@Composable
private fun ColumnScope.PlainContent(state: TangemTopNavigationStory) {
// Mirror the production `TitleSubtitle` helper so toggling the subtitle / swapping the title
// animates the same way users see in real screens. The raw `contentColumn` slot doesn't wrap
// children in any animation by itself.
val title = if (state.longTitle) LONG_TITLE else SHORT_TITLE
AnimatedContent(
targetState = title,
transitionSpec = { TitleEnterTransition togetherWith TitleExitTransition },
label = "TangemTopNavigationStory.title",
) { current ->
TangemNavigationText(text = current, role = TangemNavigationText.Role.Title)
}
val subtitle: String? = if (state.hasSubtitle) SUBTITLE else null
val displayedSubtitle = rememberLastNonNull(subtitle)
AnimatedVisibility(
visible = subtitle != null,
enter = SubtitleEnterTransition,
exit = SubtitleExitTransition,
) {
displayedSubtitle?.let { text ->
Column {
Spacer(Modifier.height(2.dp))
TangemNavigationText(text = text, role = TangemNavigationText.Role.Subtitle)
}
}
}
}
/**
* Rich content variant proves the `contentColumn` slot accepts an arbitrary composable, not just
* a plain string. Uses [AnnotatedString] with per-span colors and an inline swap emoji to mimic
* the multi-color "Title in 🔄 Title?" example from the design board.
*/
@Composable
private fun RichContent() {
val titleSpan = buildAnnotatedString {
append("Title in \uD83D\uDD04 ")
withStyle(SpanStyle(color = Color(0xFFFF4D4F))) { append("Title?") }
}
val subtitleSpan = buildAnnotatedString {
withStyle(SpanStyle(color = TangemTheme.colors3.text.secondary)) { append("Subtitle in ") }
withStyle(SpanStyle(color = Color(0xFF34C759))) { append("Subtitle?") }
}
TangemNavigationText(text = titleSpan, role = TangemNavigationText.Role.Title)
Spacer(Modifier.height(2.dp))
TangemNavigationText(text = subtitleSpan, role = TangemNavigationText.Role.Subtitle)
}
private fun endButtonContent(endButton: EndButton): (@Composable () -> Unit)? = when (endButton) {
EndButton.None -> null
EndButton.Close -> {
{ TangemButton.Close(onClick = {}) }
}
EndButton.Loader -> {
{ TangemButton(variant = TangemButton.Variant.Material, isLoading = true, onClick = {}) }
}
EndButton.HowItWorks -> {
{
TangemButton(
variant = TangemButton.Variant.Material,
text = stringReference("How it works?"),
onClick = {},
)
}
}
}
private fun endGroupContent(endGroup: EndGroup): (@Composable RowScope.() -> Unit)? = when (endGroup) {
EndGroup.None -> null
EndGroup.One -> {
{
TangemButton(
variant = TangemButton.Variant.Ghost,
iconStart = TangemIconUM.Icon(Icons.ic_arrow_swap_horizontal_20),
onClick = {},
)
}
}
EndGroup.Two -> {
{
TangemButton(
variant = TangemButton.Variant.Ghost,
iconStart = TangemIconUM.Icon(Icons.ic_arrow_swap_horizontal_20),
onClick = {},
)
TangemButton(
variant = TangemButton.Variant.Ghost,
iconStart = TangemIconUM.Icon(Icons.ic_scan_20),
onClick = {},
)
}
}
EndGroup.Three -> {
{
TangemButton(
variant = TangemButton.Variant.Ghost,
iconStart = TangemIconUM.Icon(Icons.ic_arrow_swap_horizontal_20),
onClick = {},
)
TangemButton(
variant = TangemButton.Variant.Ghost,
iconStart = TangemIconUM.Icon(Icons.ic_sign_usd_20),
onClick = {},
)
TangemButton(
variant = TangemButton.Variant.Ghost,
iconStart = TangemIconUM.Icon(Icons.ic_scan_20),
onClick = {},
)
}
}
}
@Composable
private fun PreviewBackground(background: Background, modifier: Modifier = Modifier) {
when (background) {
Background.Rainbow -> RainbowBackdrop(modifier)
Background.BgPrimary -> Box(modifier.background(TangemTheme.colors3.bg.primary))
Background.BgSecondary -> Box(modifier.background(TangemTheme.colors3.bg.secondary))
Background.BgBrand -> Box(modifier.background(TangemTheme.colors3.bg.brand))
Background.BgInverse -> Box(modifier.background(TangemTheme.colors3.bg.inverse))
}
}
@Composable
private fun RainbowBackdrop(modifier: Modifier = Modifier) {
val bands = remember {
listOf(
Color(0xFFFF1744),
Color(0xFFFF9100),
Color(0xFFFFEA00),
Color(0xFF00E676),
Color(0xFF00B8D4),
Color(0xFF2962FF),
Color(0xFFD500F9),
)
}
val stops = remember(bands) {
buildList {
bands.forEachIndexed { index, color ->
val start = index.toFloat() / bands.size
val end = (index + 1).toFloat() / bands.size
add(start to color)
add(end to color)
}
}.toTypedArray()
}
val tilePx = with(LocalDensity.current) { 160.dp.toPx() }
Box(
modifier = modifier.background(
brush = Brush.linearGradient(
colorStops = stops,
start = Offset(0f, 0f),
end = Offset(tilePx, tilePx),
tileMode = TileMode.Repeated,
),
),
)
}
@Composable
private fun ContentAlignSelector(
selected: TangemTopNavigation.ContentAlign,
onSelect: (TangemTopNavigation.ContentAlign) -> Unit,
) {
Section(label = "Content align") {
ChipGrid(
items = TangemTopNavigation.ContentAlign.entries,
label = { it.name },
isSelected = { it == selected },
onSelect = onSelect,
)
}
}
@Composable
private fun ContentModeSelector(selected: ContentMode, onSelect: (ContentMode) -> Unit) {
Section(label = "Content mode") {
ChipGrid(
items = ContentMode.entries,
label = { it.label },
isSelected = { it == selected },
onSelect = onSelect,
)
}
}
@Composable
private fun EndButtonSelector(selected: EndButton, onSelect: (EndButton) -> Unit) {
Section(label = "End button") {
ChipGrid(
items = EndButton.entries,
label = { it.label },
isSelected = { it == selected },
onSelect = onSelect,
)
}
}
@Composable
private fun EndGroupSelector(selected: EndGroup, onSelect: (EndGroup) -> Unit) {
Section(label = "End buttons group (pill)") {
ChipGrid(
items = EndGroup.entries,
label = { it.label },
isSelected = { it == selected },
onSelect = onSelect,
)
}
}
@Composable
private fun BackgroundSelector(selected: Background, onSelect: (Background) -> Unit) {
Section(label = "Background") {
ChipGrid(
items = Background.entries,
label = { it.label },
isSelected = { it == selected },
onSelect = onSelect,
)
}
}
@Composable
private fun Toggles(state: TangemTopNavigationStory) {
Section(label = "Flags") {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
ToggleRow(label = "back button", checked = state.hasBack, onToggle = state.onBackToggle)
ToggleRow(label = "subtitle", checked = state.hasSubtitle, onToggle = state.onSubtitleToggle)
ToggleRow(
label = "long title (ellipsis test)",
checked = state.longTitle,
onToggle = state.onLongTitleToggle,
)
ToggleRow(
label = "status bar insets",
checked = state.useStatusBarInsets,
onToggle = state.onStatusBarInsetsToggle,
)
ToggleRow(label = "blur (haze)", checked = state.isBlurEnabled, onToggle = state.onBlurToggle)
}
}
}
@Composable
private fun Section(label: String, content: @Composable () -> Unit) {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = label,
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
content()
}
}
@Composable
private fun <T> ChipGrid(items: List<T>, label: (T) -> String, isSelected: (T) -> Boolean, onSelect: (T) -> Unit) {
val shape = RoundedCornerShape(50)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.clip(shape)
.background(TangemTheme.colors2.surface.level2)
.border(
width = 1.dp,
color = TangemTheme.colors2.border.neutral.secondary,
shape = shape,
)
.padding(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
items.forEach { item ->
Chip(
label = label(item),
selected = isSelected(item),
onClick = { onSelect(item) },
modifier = Modifier.weight(1f),
)
}
}
}
@Composable
private fun Chip(label: String, selected: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
val chipShape = RoundedCornerShape(50)
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.clip(chipShape)
.background(
if (selected) TangemTheme.colors2.surface.level3 else TangemTheme.colors2.surface.level2,
)
.clickable(onClick = onClick)
.padding(vertical = 8.dp, horizontal = 4.dp),
) {
Text(
text = label,
style = TangemTheme.typography.caption2,
color = if (selected) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.secondary,
)
}
}
@Composable
private fun ToggleRow(label: String, checked: Boolean, onToggle: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(12.dp))
.background(TangemTheme.colors2.surface.level2)
.clickable(onClick = onToggle)
.padding(horizontal = 12.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = label,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)
Text(
text = if (checked) "ON" else "OFF",
style = TangemTheme.typography.caption2,
color = if (checked) TangemTheme.colors.text.accent else TangemTheme.colors.text.secondary,
)
}
}

View file

@ -43,6 +43,7 @@ import com.tangem.feature.tester.presentation.storybook.page.ds.fade.TangemFadeS
import com.tangem.feature.tester.presentation.storybook.page.ds.loader.TangemLoaderStory
import com.tangem.feature.tester.presentation.storybook.page.ds.row.TangemRowStory
import com.tangem.feature.tester.presentation.storybook.page.ds.shimmer.TangemShimmerStory
import com.tangem.feature.tester.presentation.storybook.page.ds.topnavigation.TangemTopNavigationStory
import com.tangem.feature.tester.presentation.storybook.page.headerrow.TangemHeaderRowStory
import com.tangem.feature.tester.presentation.storybook.page.message.TangemMessageStory
import com.tangem.feature.tester.presentation.storybook.page.opportunities.OpportunitiesBGStory
@ -93,6 +94,7 @@ internal fun StoryBookScreen(state: StoryBookUM, modifier: Modifier = Modifier)
is TangemRowStory -> TangemRowStory(state = storyState)
is TangemShimmerStory -> TangemShimmerStory(state = storyState)
is TangemFadeStory -> TangemFadeStory(state = storyState)
is TangemTopNavigationStory -> TangemTopNavigationStory(state = storyState)
}
}
}