commit 25a69d06371dc855e297c9f57d34756730109ba2 parent c74db430f82ee4f85dafd5a19a6839aa907b52d8 Author: triesap <tyson@radroots.org> Date: Thu, 13 Aug 2026 15:30:51 +0000 design: port HarvestCircle content components - own card and dialog containers with semantic surfaces - port banner tooltip and progress feedback components - preserve compact desktop geometry and interaction states - retain visible focus defaults for clickable content Diffstat:
6 files changed, 694 insertions(+), 0 deletions(-)
diff --git a/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/container/HarvestCircleCard.kt b/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/container/HarvestCircleCard.kt @@ -0,0 +1,230 @@ +package org.harvestcircle.designsystem.component.container + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.lerp +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import org.harvestcircle.designsystem.component.HarvestCircleContentTone +import org.harvestcircle.designsystem.component.HarvestCircleFocusRing +import org.harvestcircle.designsystem.component.HarvestCircleTextRole +import org.harvestcircle.designsystem.internal.chrome.HarvestCircleMacFocusFrame +import org.harvestcircle.designsystem.internal.interaction.harvestCircleHoverable +import org.harvestcircle.designsystem.internal.interaction.harvestCircleInteractions +import org.harvestcircle.designsystem.internal.interaction.rememberHarvestCircleInteractionSources +import org.harvestcircle.designsystem.primitive.HarvestCircleText +import org.harvestcircle.designsystem.primitive.ProvideHarvestCircleContentColor +import org.harvestcircle.designsystem.theme.HarvestCircleTheme + +public enum class HarvestCircleCardVariant { + Default, + Raised, + Outlined, + Selected, +} + +public enum class HarvestCircleCardPadding { + None, + Compact, + Default, +} + +private data class CardVisuals( + val color: Color, + val border: BorderStroke?, + val elevation: Dp, +) + +@Composable +private fun cardVisuals(variant: HarvestCircleCardVariant): CardVisuals = + when (variant) { + HarvestCircleCardVariant.Default -> + CardVisuals( + color = HarvestCircleTheme.foundation.colors.surface.base, + border = BorderStroke(1.dp, HarvestCircleTheme.foundation.colors.border.subtle), + elevation = HarvestCircleTheme.component.elevations.flat, + ) + + HarvestCircleCardVariant.Raised -> + CardVisuals( + color = HarvestCircleTheme.foundation.colors.surface.raised, + border = BorderStroke(1.dp, HarvestCircleTheme.foundation.colors.border.subtle), + elevation = HarvestCircleTheme.component.elevations.raised, + ) + + HarvestCircleCardVariant.Outlined -> + CardVisuals( + color = HarvestCircleTheme.foundation.colors.surface.base, + border = BorderStroke(1.dp, HarvestCircleTheme.foundation.colors.border.default), + elevation = HarvestCircleTheme.component.elevations.flat, + ) + + HarvestCircleCardVariant.Selected -> + CardVisuals( + color = HarvestCircleTheme.foundation.colors.surface.selected, + border = BorderStroke(1.dp, HarvestCircleTheme.foundation.colors.border.selected), + elevation = HarvestCircleTheme.component.elevations.flat, + ) + } + +@Composable +private fun cardPadding(padding: HarvestCircleCardPadding): PaddingValues = + when (padding) { + HarvestCircleCardPadding.None -> PaddingValues(0.dp) + HarvestCircleCardPadding.Compact -> PaddingValues(HarvestCircleTheme.foundation.spacing.md) + HarvestCircleCardPadding.Default -> PaddingValues(HarvestCircleTheme.foundation.spacing.lg) + } + +@Composable +private fun HarvestCircleCardFrame( + color: Color, + border: BorderStroke?, + elevation: Dp, + modifier: Modifier = Modifier, + padding: HarvestCircleCardPadding, + content: @Composable BoxScope.() -> Unit, +) { + ProvideHarvestCircleContentColor(HarvestCircleTheme.foundation.colors.content.primary) { + Box( + modifier = + modifier + .then( + if (elevation > 0.dp) { + Modifier.shadow(elevation, HarvestCircleTheme.foundation.shapes.card, clip = false) + } else { + Modifier + }, + ).clip(HarvestCircleTheme.foundation.shapes.card) + .background(color) + .then( + if (border != null) { + Modifier.border(border, HarvestCircleTheme.foundation.shapes.card) + } else { + Modifier + }, + ).padding(cardPadding(padding)), + content = content, + ) + } +} + +/** Flat AppKit group/card container. */ +@Composable +public fun HarvestCircleCard( + modifier: Modifier = Modifier, + variant: HarvestCircleCardVariant = HarvestCircleCardVariant.Default, + padding: HarvestCircleCardPadding = HarvestCircleCardPadding.Default, + content: @Composable BoxScope.() -> Unit, +) { + val visuals = cardVisuals(variant) + HarvestCircleCardFrame( + color = visuals.color, + border = visuals.border, + elevation = visuals.elevation, + modifier = modifier, + padding = padding, + content = content, + ) +} + +/** Clickable card with Foundation interaction semantics and no Material surface behavior. */ +@Composable +public fun HarvestCircleClickableCard( + onClick: () -> Unit, + modifier: Modifier = Modifier, + variant: HarvestCircleCardVariant = HarvestCircleCardVariant.Default, + padding: HarvestCircleCardPadding = HarvestCircleCardPadding.Default, + enabled: Boolean = true, + focusRing: HarvestCircleFocusRing = HarvestCircleFocusRing.WhenFocused, + content: @Composable BoxScope.() -> Unit, +) { + val sources = rememberHarvestCircleInteractionSources() + val interactions = sources.harvestCircleInteractions(enabled) + val visuals = cardVisuals(variant) + val color = + when { + !enabled -> visuals.color + interactions.pressed -> + lerp(visuals.color, HarvestCircleTheme.foundation.colors.action.ghost.pressed, 0.55f) + interactions.hovered -> + lerp(visuals.color, HarvestCircleTheme.foundation.colors.action.ghost.hover, 0.40f) + else -> visuals.color + } + + Box( + modifier = + modifier + .harvestCircleHoverable(sources = sources, enabled = enabled) + .clickable( + interactionSource = sources.activationSource, + indication = null, + enabled = enabled, + role = Role.Button, + onClick = onClick, + ), + contentAlignment = Alignment.Center, + ) { + HarvestCircleMacFocusFrame( + focused = interactions.focused, + focusRing = focusRing, + modifier = Modifier.fillMaxWidth(), + shape = HarvestCircleTheme.foundation.shapes.card, + ringShape = HarvestCircleTheme.foundation.shapes.cardFocusRing, + ) { + HarvestCircleCardFrame( + color = color, + border = visuals.border, + elevation = visuals.elevation, + modifier = Modifier.fillMaxWidth(), + padding = padding, + content = content, + ) + } + } +} + +/** Canonical labeled group box for settings and inspector forms. */ +@Composable +public fun HarvestCircleGroupBox( + modifier: Modifier = Modifier, + title: String? = null, + content: @Composable ColumnScope.() -> Unit, +) { + Column(modifier = modifier) { + if (title != null) { + HarvestCircleText( + text = title, + modifier = + Modifier.padding( + start = HarvestCircleTheme.foundation.spacing.sm, + bottom = HarvestCircleTheme.foundation.spacing.xs, + ), + role = HarvestCircleTextRole.LabelSmall, + tone = HarvestCircleContentTone.Secondary, + ) + } + + HarvestCircleCard( + variant = HarvestCircleCardVariant.Outlined, + padding = HarvestCircleCardPadding.Default, + ) { + Column(content = content) + } + } +} diff --git a/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/container/HarvestCircleDialog.kt b/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/container/HarvestCircleDialog.kt @@ -0,0 +1,149 @@ +package org.harvestcircle.designsystem.component.container + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.semantics.paneTitle +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import org.harvestcircle.designsystem.component.HarvestCircleButtonVariant +import org.harvestcircle.designsystem.component.HarvestCircleContentTone +import org.harvestcircle.designsystem.component.HarvestCircleFocusRing +import org.harvestcircle.designsystem.component.HarvestCircleTextRole +import org.harvestcircle.designsystem.component.action.HarvestCircleButton +import org.harvestcircle.designsystem.focus.HarvestCircleFocusDismissBehavior +import org.harvestcircle.designsystem.internal.focus.harvestCircleClearFocusOnBackgroundPress +import org.harvestcircle.designsystem.primitive.HarvestCircleSurface +import org.harvestcircle.designsystem.primitive.HarvestCircleSurfaceRole +import org.harvestcircle.designsystem.primitive.HarvestCircleText +import org.harvestcircle.designsystem.theme.HarvestCircleTheme + +/** Canonical macOS alert sheet/panel treatment implemented with Compose Dialog primitives. */ +@Composable +public fun HarvestCircleDialog( + onDismissRequest: () -> Unit, + title: String, + message: String, + confirmLabel: String, + onConfirm: () -> Unit, + modifier: Modifier = Modifier, + dismissLabel: String? = null, + onDismiss: (() -> Unit)? = null, + destructive: Boolean = false, + focusRing: HarvestCircleFocusRing = HarvestCircleFocusRing.WhenFocused, + focusDismissBehavior: HarvestCircleFocusDismissBehavior = + HarvestCircleFocusDismissBehavior.ClearOnBackgroundPress, + forceFocusDismissal: Boolean = false, +) { + require((dismissLabel == null) == (onDismiss == null)) { + "dismissLabel and onDismiss must either both be supplied or both be null" + } + + val defaultFocusRequester = remember { FocusRequester() } + val focusDismiss = destructive && dismissLabel != null + + Dialog(onDismissRequest = onDismissRequest) { + val focusManager = LocalFocusManager.current + LaunchedEffect(defaultFocusRequester, focusDismiss) { + defaultFocusRequester.requestFocus() + } + + HarvestCircleSurface( + modifier = + modifier + .widthIn(min = 360.dp, max = 480.dp) + .harvestCircleClearFocusOnBackgroundPress( + focusManager = focusManager, + enabled = + focusDismissBehavior == + HarvestCircleFocusDismissBehavior.ClearOnBackgroundPress, + force = forceFocusDismissal, + ).semantics { paneTitle = title }, + role = HarvestCircleSurfaceRole.Overlay, + shape = HarvestCircleTheme.foundation.shapes.dialog, + border = BorderStroke(1.dp, HarvestCircleTheme.foundation.colors.border.subtle), + shadowElevation = HarvestCircleTheme.component.elevations.dialog, + ) { + Column( + modifier = Modifier.padding(HarvestCircleTheme.foundation.spacing.xl), + verticalArrangement = Arrangement.spacedBy(HarvestCircleTheme.foundation.spacing.lg), + ) { + Column( + verticalArrangement = Arrangement.spacedBy(HarvestCircleTheme.foundation.spacing.sm), + ) { + HarvestCircleText( + text = title, + role = HarvestCircleTextRole.SectionTitle, + ) + HarvestCircleText( + text = message, + role = HarvestCircleTextRole.Body, + tone = HarvestCircleContentTone.Secondary, + ) + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(HarvestCircleTheme.foundation.spacing.md, Alignment.End), + verticalAlignment = Alignment.CenterVertically, + ) { + if (dismissLabel != null && onDismiss != null) { + HarvestCircleButton( + onClick = onDismiss, + modifier = + if (focusDismiss) { + Modifier.focusRequester(defaultFocusRequester) + } else { + Modifier + }, + variant = HarvestCircleButtonVariant.Secondary, + focusRing = focusRing, + ) { + HarvestCircleText( + text = dismissLabel, + role = HarvestCircleTextRole.Label, + tone = HarvestCircleContentTone.Inherit, + ) + } + } + + HarvestCircleButton( + onClick = onConfirm, + modifier = + if (!focusDismiss) { + Modifier.focusRequester(defaultFocusRequester) + } else { + Modifier + }, + variant = + if (destructive) { + HarvestCircleButtonVariant.Destructive + } else { + HarvestCircleButtonVariant.Primary + }, + focusRing = focusRing, + ) { + HarvestCircleText( + text = confirmLabel, + role = HarvestCircleTextRole.Label, + tone = HarvestCircleContentTone.Inherit, + ) + } + } + } + } + } +} diff --git a/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/feedback/HarvestCircleBanner.kt b/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/feedback/HarvestCircleBanner.kt @@ -0,0 +1,106 @@ +package org.harvestcircle.designsystem.component.feedback + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import org.harvestcircle.designsystem.component.HarvestCircleContentTone +import org.harvestcircle.designsystem.component.HarvestCircleIconSize +import org.harvestcircle.designsystem.component.HarvestCircleTextRole +import org.harvestcircle.designsystem.icon.HarvestCircleIcons +import org.harvestcircle.designsystem.primitive.HarvestCircleIcon +import org.harvestcircle.designsystem.primitive.HarvestCircleSurface +import org.harvestcircle.designsystem.primitive.HarvestCircleSurfaceRole +import org.harvestcircle.designsystem.primitive.HarvestCircleText +import org.harvestcircle.designsystem.primitive.ProvideHarvestCircleContentColor +import org.harvestcircle.designsystem.theme.HarvestCircleTheme +import org.harvestcircle.designsystem.theme.color.HarvestCircleFeedbackRoleColors +import org.jetbrains.compose.resources.DrawableResource + +public enum class HarvestCircleBannerTone { + Info, + Success, + Warning, + Error, +} + +@Composable +private fun roleColors(tone: HarvestCircleBannerTone): HarvestCircleFeedbackRoleColors = + when (tone) { + HarvestCircleBannerTone.Info -> HarvestCircleTheme.foundation.colors.feedback.info + HarvestCircleBannerTone.Success -> HarvestCircleTheme.foundation.colors.feedback.success + HarvestCircleBannerTone.Warning -> HarvestCircleTheme.foundation.colors.feedback.warning + HarvestCircleBannerTone.Error -> HarvestCircleTheme.foundation.colors.feedback.error + } + +private fun defaultIcon(tone: HarvestCircleBannerTone): DrawableResource = + when (tone) { + HarvestCircleBannerTone.Info -> HarvestCircleIcons.Info + HarvestCircleBannerTone.Success -> HarvestCircleIcons.Check + HarvestCircleBannerTone.Warning, + HarvestCircleBannerTone.Error, + -> HarvestCircleIcons.Warning + } + +/** Compact inline status well modeled after canonical macOS informational callouts. */ +@Composable +public fun HarvestCircleBanner( + message: String, + modifier: Modifier = Modifier, + tone: HarvestCircleBannerTone = HarvestCircleBannerTone.Info, + title: String? = null, + icon: DrawableResource = defaultIcon(tone), + action: (@Composable RowScope.() -> Unit)? = null, +) { + val colors = roleColors(tone) + + HarvestCircleSurface( + modifier = modifier, + role = HarvestCircleSurfaceRole.Base, + shape = HarvestCircleTheme.foundation.shapes.card, + border = BorderStroke(1.dp, colors.border), + color = colors.subtle, + contentColor = colors.onSubtle, + ) { + ProvideHarvestCircleContentColor(colors.onSubtle) { + Row( + modifier = Modifier.padding(HarvestCircleTheme.foundation.spacing.lg), + horizontalArrangement = Arrangement.spacedBy(HarvestCircleTheme.foundation.spacing.md), + verticalAlignment = Alignment.CenterVertically, + ) { + HarvestCircleIcon( + resource = icon, + contentDescription = null, + size = HarvestCircleIconSize.Medium, + tone = HarvestCircleContentTone.Inherit, + ) + + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(HarvestCircleTheme.foundation.spacing.xs), + ) { + if (title != null) { + HarvestCircleText( + text = title, + role = HarvestCircleTextRole.BodyStrong, + tone = HarvestCircleContentTone.Inherit, + ) + } + HarvestCircleText( + text = message, + role = HarvestCircleTextRole.Body, + tone = HarvestCircleContentTone.Inherit, + ) + } + + action?.invoke(this) + } + } + } +} diff --git a/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/feedback/HarvestCircleProgressIndicator.kt b/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/feedback/HarvestCircleProgressIndicator.kt @@ -0,0 +1,46 @@ +package org.harvestcircle.designsystem.component.feedback + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.ProgressBarRangeInfo +import androidx.compose.ui.semantics.progressBarRangeInfo +import androidx.compose.ui.semantics.semantics +import org.harvestcircle.designsystem.internal.progress.HarvestCircleMacIndeterminateBar +import org.harvestcircle.designsystem.internal.progress.HarvestCircleMacSpinner +import org.harvestcircle.designsystem.theme.HarvestCircleTheme + +public enum class HarvestCircleProgressKind { + Circular, + Linear, +} + +/** Canonical indeterminate macOS spinner or progress bar, rendered without Material indicators. */ +@Composable +public fun HarvestCircleProgressIndicator( + modifier: Modifier = Modifier, + kind: HarvestCircleProgressKind = HarvestCircleProgressKind.Circular, +) { + when (kind) { + HarvestCircleProgressKind.Circular -> + HarvestCircleMacSpinner( + modifier = + modifier.semantics { + progressBarRangeInfo = ProgressBarRangeInfo.Indeterminate + }, + size = HarvestCircleTheme.shell.dimensions.iconLarge, + color = HarvestCircleTheme.foundation.colors.content.secondary, + ) + + HarvestCircleProgressKind.Linear -> + HarvestCircleMacIndeterminateBar( + modifier = + modifier + .fillMaxWidth() + .semantics { + progressBarRangeInfo = ProgressBarRangeInfo.Indeterminate + }, + color = HarvestCircleTheme.foundation.colors.action.primary.rest, + ) + } +} diff --git a/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/feedback/HarvestCircleTooltip.kt b/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/feedback/HarvestCircleTooltip.kt @@ -0,0 +1,112 @@ +@file:OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class) + +package org.harvestcircle.designsystem.component.feedback + +import androidx.compose.foundation.BasicTooltipBox +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberBasicTooltipState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntRect +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.PopupPositionProvider +import org.harvestcircle.designsystem.component.HarvestCircleContentTone +import org.harvestcircle.designsystem.component.HarvestCircleTextRole +import org.harvestcircle.designsystem.primitive.HarvestCircleSurface +import org.harvestcircle.designsystem.primitive.HarvestCircleSurfaceRole +import org.harvestcircle.designsystem.primitive.HarvestCircleText +import org.harvestcircle.designsystem.primitive.ProvideHarvestCircleContentColor +import org.harvestcircle.designsystem.theme.HarvestCircleTheme + +/** Compact AppKit-style tooltip triggered by pointer hover or touch long press. */ +@Composable +public fun HarvestCircleTooltip( + text: String, + modifier: Modifier = Modifier, + content: @Composable () -> Unit, +) { + val state = rememberBasicTooltipState(isPersistent = true) + val density = LocalDensity.current + val gapPx = with(density) { 6.dp.roundToPx() } + val positionProvider = + remember(gapPx) { + object : PopupPositionProvider { + override fun calculatePosition( + anchorBounds: IntRect, + windowSize: IntSize, + layoutDirection: LayoutDirection, + popupContentSize: IntSize, + ): IntOffset { + val centeredX = + anchorBounds.left + (anchorBounds.width - popupContentSize.width) / 2 + val clampedX = + centeredX.coerceIn( + minimumValue = 0, + maximumValue = + (windowSize.width - popupContentSize.width).coerceAtLeast(0), + ) + val above = anchorBounds.top - popupContentSize.height - gapPx + val y = + if (above >= 0) { + above + } else { + (anchorBounds.bottom + gapPx) + .coerceAtMost((windowSize.height - popupContentSize.height).coerceAtLeast(0)) + } + return IntOffset(clampedX, y) + } + } + } + + val container = + if (HarvestCircleTheme.foundation.colors.isDark) { + HarvestCircleTheme.foundation.colors.surface.raised + } else { + HarvestCircleTheme.foundation.colors.content.primary + } + val contentColor = + if (HarvestCircleTheme.foundation.colors.isDark) { + HarvestCircleTheme.foundation.colors.content.primary + } else { + HarvestCircleTheme.foundation.colors.content.inverse + } + + BasicTooltipBox( + positionProvider = positionProvider, + tooltip = { + HarvestCircleSurface( + role = HarvestCircleSurfaceRole.Overlay, + shape = HarvestCircleTheme.foundation.shapes.control, + border = BorderStroke(1.dp, HarvestCircleTheme.foundation.colors.border.strong), + shadowElevation = HarvestCircleTheme.component.elevations.overlay, + color = container, + contentColor = contentColor, + ) { + ProvideHarvestCircleContentColor(contentColor) { + HarvestCircleText( + text = text, + modifier = + Modifier.padding( + horizontal = HarvestCircleTheme.foundation.spacing.md, + vertical = HarvestCircleTheme.foundation.spacing.xs, + ), + role = HarvestCircleTextRole.BodySmall, + tone = HarvestCircleContentTone.Inherit, + maxLines = 3, + ) + } + } + }, + state = state, + modifier = modifier, + focusable = false, + enableUserInput = true, + content = content, + ) +} diff --git a/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/utility/HarvestCircleDivider.kt b/app/design_system/src/commonMain/kotlin/org/harvestcircle/designsystem/component/utility/HarvestCircleDivider.kt @@ -0,0 +1,51 @@ +package org.harvestcircle.designsystem.component.utility + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import org.harvestcircle.designsystem.theme.HarvestCircleTheme + +@Composable +public fun HarvestCircleHorizontalDivider( + modifier: Modifier = Modifier, + strong: Boolean = false, +) { + Box( + modifier = + modifier + .fillMaxWidth() + .height(HarvestCircleTheme.shell.dimensions.dividerWidth) + .background( + if (strong) { + HarvestCircleTheme.foundation.colors.border.default + } else { + HarvestCircleTheme.foundation.colors.border.subtle + }, + ), + ) +} + +@Composable +public fun HarvestCircleVerticalDivider( + modifier: Modifier = Modifier, + strong: Boolean = false, +) { + Box( + modifier = + modifier + .fillMaxHeight() + .width(HarvestCircleTheme.shell.dimensions.dividerWidth) + .background( + if (strong) { + HarvestCircleTheme.foundation.colors.border.default + } else { + HarvestCircleTheme.foundation.colors.border.subtle + }, + ), + ) +}