From 1184ff73075163cba2babf3c12f3366ccdf948e6 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 00:25:51 +0300 Subject: [PATCH 01/75] feat(ui): components interfaces --- .../ui/shared/stories/ComponentExample.kt | 9 +++ .../ui/shared/stories/ComponentVariants.kt | 66 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentExample.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentExample.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentExample.kt new file mode 100644 index 000000000..57b1be834 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentExample.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.shared.stories + +import androidx.compose.runtime.Composable + +interface ComponentExample { + val name: String + @Composable + fun Content() +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt new file mode 100644 index 000000000..8009b90ad --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt @@ -0,0 +1,66 @@ +package com.atls.hyperion.ui.shared.stories + +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.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.atls.hyperion.ui.theme.typography.FontSize + +@Composable +fun ComponentVariants( + name: String, + appearances: List T>>, + shapes: List S>>, + component: @Composable (appearance: T, shape: S) -> Unit +) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = name, + fontSize = FontSize.large, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(bottom = 16.dp) + ) + + LazyColumn(verticalArrangement = Arrangement.spacedBy(24.dp)) { + items(appearances) { (appearanceName, appearanceProvider) -> + val appearance = appearanceProvider() + Column { + Text( + text = "Appearance: $appearanceName", + fontWeight = FontWeight.SemiBold, + modifier = Modifier.padding(bottom = 8.dp) + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + shapes.forEach { (shapeName, shapeProvider) -> + val shape = shapeProvider() + Column(horizontalAlignment = Alignment.CenterHorizontally) { + component(appearance, shape) + Text( + text = shapeName, + fontSize = 12.sp, + modifier = Modifier.padding(top = 4.dp) + ) + } + } + } + Divider(modifier = Modifier.padding(top = 16.dp)) + } + } + } + } +} From 1265115efd1ac0c3262c8cbf4f2e995263f8dc44 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 00:26:19 +0300 Subject: [PATCH 02/75] feat(common): storybook resources --- .../sample/src/commonMain/composeResources/drawable/menu.xml | 5 +++++ .../src/commonMain/composeResources/values/strings.xml | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml create mode 100644 mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml diff --git a/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml b/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml new file mode 100644 index 000000000..9e7f0e919 --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml b/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 000000000..c2e3d112a --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,5 @@ + + Components + Select a component from the sidebar + Toggle Sidebar + From b3d1916986ecb68e1b06c08d21cd334fab5bab83 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 00:26:31 +0300 Subject: [PATCH 03/75] feat(app): storybook sidebar --- .../atls/hyperion/sample/storybook/Sidebar.kt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt new file mode 100644 index 000000000..9c8fc0fd3 --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt @@ -0,0 +1,74 @@ +package com.atls.hyperion.sample.storybook + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Divider +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.atls.hyperion.ui.shared.stories.ComponentExample +import com.atls.hyperion.ui.theme.tokens.Space +import com.atls.hyperion.ui.theme.typography.FontSize +import hyperion.sample.generated.resources.Res +import hyperion.sample.generated.resources.components +import org.jetbrains.compose.resources.stringResource + +@Composable +fun Sidebar( + components: List, + selectedComponent: ComponentExample?, + onComponentClick: (ComponentExample) -> Unit, + onClose: () -> Unit +) { + Box( + modifier = Modifier + .fillMaxSize() + .clickable { onClose() } + ) { + Surface( + modifier = Modifier + .fillMaxHeight() + .width(250.dp), + color = MaterialTheme.colors.surface + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(Space.g14) + ) { + Text( + text = stringResource(Res.string.components), + fontSize = FontSize.large, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(vertical = Space.g24) + ) + LazyColumn { + items(components) { component -> + Text( + text = component.name, + modifier = Modifier + .fillMaxWidth() + .clickable { onComponentClick(component) } + .padding(vertical = Space.g12), + fontWeight = if (component == selectedComponent) FontWeight.Bold else FontWeight.Normal, + fontSize = FontSize.medium + ) + Divider() + } + } + } + } + } +} From b8ddfe84cf12d639177385ef153c3711514101c4 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 00:26:38 +0300 Subject: [PATCH 04/75] feat(app): storybook component --- .../hyperion/sample/storybook/Storybook.kt | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt new file mode 100644 index 000000000..3cd112f85 --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt @@ -0,0 +1,89 @@ +package com.atls.hyperion.sample.storybook + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.shared.stories.ComponentExample +import com.atls.hyperion.ui.theme.tokens.Space +import hyperion.sample.generated.resources.Res +import hyperion.sample.generated.resources.menu +import hyperion.sample.generated.resources.select_component_from_sidebar +import hyperion.sample.generated.resources.toggle_sidebar +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource + +@Composable +fun Storybook( + components: List +) { + var isSidebarVisible by remember { mutableStateOf(false) } + var selectedComponent by remember(components) { + mutableStateOf(components.firstOrNull()) + } + + Box { + Column( + modifier = Modifier + .fillMaxSize() + .safeDrawingPadding() + ) { + IconButton( + onClick = { isSidebarVisible = !isSidebarVisible }, + modifier = Modifier + .padding(Space.g12) + ) { + Icon( + painter = painterResource(Res.drawable.menu), + contentDescription = stringResource(Res.string.toggle_sidebar), + tint = MaterialTheme.colors.onSurface + ) + } + Box( + modifier = Modifier + .fillMaxSize() + ) { + if (selectedComponent != null) { + selectedComponent?.Content() + } else { + Text( + text = stringResource(Res.string.select_component_from_sidebar), + modifier = Modifier + .align(Alignment.Center), + ) + } + } + } + + AnimatedVisibility( + visible = isSidebarVisible, + enter = slideInHorizontally(), + exit = slideOutHorizontally() + ) { + Sidebar( + components = components, + selectedComponent = selectedComponent, + onComponentClick = { component -> + selectedComponent = component + isSidebarVisible = false + }, + onClose = { isSidebarVisible = false } + ) + } + } +} From c54afd811fa869d5c08fed2c2e0df48665ba3ad3 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 01:04:26 +0300 Subject: [PATCH 05/75] refactor(common): extract storybook to separate module --- mobile/kmp/sample/build.gradle.kts | 1 + .../kotlin/com/atls/hyperion/sample/App.kt | 20 +++--- mobile/kmp/settings.gradle.kts | 2 + mobile/kmp/storybook/.gitignore | 1 + mobile/kmp/storybook/build.gradle.kts | 65 ++++++++++++++++++ .../composeResources/drawable/menu.xml | 0 .../composeResources/values/strings.xml | 0 .../hyperion/storybook}/ComponentExample.kt | 2 +- .../hyperion/storybook/ComponentVariants.kt | 65 ++++++++++++++++++ .../com/atls/hyperion}/storybook/Sidebar.kt | 20 +++--- .../com/atls/hyperion}/storybook/Storybook.kt | 15 ++--- mobile/kmp/ui/build.gradle.kts | 1 + .../ui/shared/stories/ComponentVariants.kt | 66 ------------------- 13 files changed, 160 insertions(+), 98 deletions(-) create mode 100644 mobile/kmp/storybook/.gitignore create mode 100644 mobile/kmp/storybook/build.gradle.kts rename mobile/kmp/{sample => storybook}/src/commonMain/composeResources/drawable/menu.xml (100%) rename mobile/kmp/{sample => storybook}/src/commonMain/composeResources/values/strings.xml (100%) rename mobile/kmp/{ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories => storybook/src/commonMain/kotlin/com/atls/hyperion/storybook}/ComponentExample.kt (74%) create mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt rename mobile/kmp/{sample/src/commonMain/kotlin/com/atls/hyperion/sample => storybook/src/commonMain/kotlin/com/atls/hyperion}/storybook/Sidebar.kt (79%) rename mobile/kmp/{sample/src/commonMain/kotlin/com/atls/hyperion/sample => storybook/src/commonMain/kotlin/com/atls/hyperion}/storybook/Storybook.kt (87%) delete mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt diff --git a/mobile/kmp/sample/build.gradle.kts b/mobile/kmp/sample/build.gradle.kts index 21086ddc7..da45f15ec 100644 --- a/mobile/kmp/sample/build.gradle.kts +++ b/mobile/kmp/sample/build.gradle.kts @@ -28,6 +28,7 @@ kotlin { sourceSets { commonMain.dependencies { implementation(project(":ui")) + implementation(project(":storybook")) implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt index 5c31d68ad..552faf06e 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt @@ -1,22 +1,18 @@ package com.atls.hyperion.sample -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import com.atls.hyperion.storybook.Storybook +import com.atls.hyperion.ui.components.button.stories.ButtonExample @Composable fun App() { MaterialTheme { - Column( - modifier = Modifier - .fillMaxSize() - .padding(16.dp) - ) { - //TODO use for demonstration and tests - } + Storybook( + components = listOf( + ButtonExample(), + ButtonExample() + ) + ) } } diff --git a/mobile/kmp/settings.gradle.kts b/mobile/kmp/settings.gradle.kts index f3b45bbcc..583813c1d 100644 --- a/mobile/kmp/settings.gradle.kts +++ b/mobile/kmp/settings.gradle.kts @@ -16,3 +16,5 @@ dependencyResolutionManagement { rootProject.name = "hyperion" include(":sample") include(":ui") +include(":storybook") +include(":storybook-api") diff --git a/mobile/kmp/storybook/.gitignore b/mobile/kmp/storybook/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/mobile/kmp/storybook/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mobile/kmp/storybook/build.gradle.kts b/mobile/kmp/storybook/build.gradle.kts new file mode 100644 index 000000000..f77186dec --- /dev/null +++ b/mobile/kmp/storybook/build.gradle.kts @@ -0,0 +1,65 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.androidLibrary) + alias(libs.plugins.composeMultiplatform) + alias(libs.plugins.composeCompiler) +} + +group = "com.atls.hyperion" +version = "0.1.0" + +kotlin { + androidTarget { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } + } + + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { iosTarget -> + iosTarget.binaries.framework { + baseName = "storybook" + isStatic = true + } + } + + sourceSets { + commonMain.dependencies { + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + implementation(compose.ui) + implementation(compose.components.resources) + } + } +} + +compose.resources { + publicResClass = false + generateResClass = auto +} + +android { + namespace = "com.atls.hyperion.storybook" + + val compileSdkValue = System.getenv(Versions.COMPILE_SDK_KEY)?.toInt() + ?: (extra[Versions.COMPILE_SDK_KEY] as String).toInt() + val minSdkValue = System.getenv(Versions.MIN_SDK_KEY)?.toInt() + ?: (extra[Versions.MIN_SDK_KEY] as String).toInt() + val javaTargetValue = System.getenv(Versions.JAVA_TARGET_KEY)?.toInt() + ?: (extra[Versions.JAVA_TARGET_KEY] as String).toInt() + + compileSdk = compileSdkValue + defaultConfig { + minSdk = minSdkValue + } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(javaTargetValue) + targetCompatibility = JavaVersion.toVersion(javaTargetValue) + } +} diff --git a/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml b/mobile/kmp/storybook/src/commonMain/composeResources/drawable/menu.xml similarity index 100% rename from mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml rename to mobile/kmp/storybook/src/commonMain/composeResources/drawable/menu.xml diff --git a/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml b/mobile/kmp/storybook/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml rename to mobile/kmp/storybook/src/commonMain/composeResources/values/strings.xml diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentExample.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt similarity index 74% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentExample.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt index 57b1be834..ecc04bf45 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentExample.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.shared.stories +package com.atls.hyperion.storybook import androidx.compose.runtime.Composable diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt new file mode 100644 index 000000000..de2e5163f --- /dev/null +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt @@ -0,0 +1,65 @@ +package com.atls.hyperion.storybook + +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.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun ComponentVariants( + name: String, + appearances: List A>>, + shapes: List S>>, + content: @Composable (A, S) -> Unit +) { + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + Text( + text = name, + fontSize = 24.sp, + fontWeight = FontWeight.Bold + ) + + appearances.forEach { (appearanceName, appearanceProvider) -> + Column( + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text( + text = appearanceName, + fontSize = 20.sp, + fontWeight = FontWeight.SemiBold + ) + + shapes.forEach { (shapeName, shapeProvider) -> + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = shapeName, + fontSize = 16.sp, + modifier = Modifier.padding(top = 8.dp) + ) + content(appearanceProvider(), shapeProvider()) + } + Divider() + } + } + } + } +} diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt similarity index 79% rename from mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt index 9c8fc0fd3..c5b1e15a0 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.sample.storybook +package com.atls.hyperion.storybook import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -18,11 +18,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.atls.hyperion.ui.shared.stories.ComponentExample -import com.atls.hyperion.ui.theme.tokens.Space -import com.atls.hyperion.ui.theme.typography.FontSize -import hyperion.sample.generated.resources.Res -import hyperion.sample.generated.resources.components +import androidx.compose.ui.unit.sp +import com.atls.hyperion.storybook.generated.resources.Res +import com.atls.hyperion.storybook.generated.resources.components import org.jetbrains.compose.resources.stringResource @Composable @@ -46,13 +44,13 @@ fun Sidebar( Column( modifier = Modifier .fillMaxSize() - .padding(Space.g14) + .padding(14.dp) ) { Text( text = stringResource(Res.string.components), - fontSize = FontSize.large, + fontSize = 20.sp, fontWeight = FontWeight.Bold, - modifier = Modifier.padding(vertical = Space.g24) + modifier = Modifier.padding(vertical = 24.dp) ) LazyColumn { items(components) { component -> @@ -61,9 +59,9 @@ fun Sidebar( modifier = Modifier .fillMaxWidth() .clickable { onComponentClick(component) } - .padding(vertical = Space.g12), + .padding(vertical = 12.dp), fontWeight = if (component == selectedComponent) FontWeight.Bold else FontWeight.Normal, - fontSize = FontSize.medium + fontSize = 16.sp ) Divider() } diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt similarity index 87% rename from mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt index 3cd112f85..5dcb0b102 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.sample.storybook +package com.atls.hyperion.storybook import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.slideInHorizontally @@ -19,12 +19,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import com.atls.hyperion.ui.shared.stories.ComponentExample -import com.atls.hyperion.ui.theme.tokens.Space -import hyperion.sample.generated.resources.Res -import hyperion.sample.generated.resources.menu -import hyperion.sample.generated.resources.select_component_from_sidebar -import hyperion.sample.generated.resources.toggle_sidebar +import androidx.compose.ui.unit.dp +import com.atls.hyperion.storybook.generated.resources.Res +import com.atls.hyperion.storybook.generated.resources.menu +import com.atls.hyperion.storybook.generated.resources.select_component_from_sidebar +import com.atls.hyperion.storybook.generated.resources.toggle_sidebar import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -46,7 +45,7 @@ fun Storybook( IconButton( onClick = { isSidebarVisible = !isSidebarVisible }, modifier = Modifier - .padding(Space.g12) + .padding(12.dp) ) { Icon( painter = painterResource(Res.drawable.menu), diff --git a/mobile/kmp/ui/build.gradle.kts b/mobile/kmp/ui/build.gradle.kts index 4a24bfd64..6b5b6adf3 100644 --- a/mobile/kmp/ui/build.gradle.kts +++ b/mobile/kmp/ui/build.gradle.kts @@ -30,6 +30,7 @@ kotlin { sourceSets { commonMain.dependencies { + api(project(":storybook")) implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt deleted file mode 100644 index 8009b90ad..000000000 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/stories/ComponentVariants.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.atls.hyperion.ui.shared.stories - -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.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material.Divider -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.atls.hyperion.ui.theme.typography.FontSize - -@Composable -fun ComponentVariants( - name: String, - appearances: List T>>, - shapes: List S>>, - component: @Composable (appearance: T, shape: S) -> Unit -) { - Column(modifier = Modifier.padding(16.dp)) { - Text( - text = name, - fontSize = FontSize.large, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(bottom = 16.dp) - ) - - LazyColumn(verticalArrangement = Arrangement.spacedBy(24.dp)) { - items(appearances) { (appearanceName, appearanceProvider) -> - val appearance = appearanceProvider() - Column { - Text( - text = "Appearance: $appearanceName", - fontWeight = FontWeight.SemiBold, - modifier = Modifier.padding(bottom = 8.dp) - ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - shapes.forEach { (shapeName, shapeProvider) -> - val shape = shapeProvider() - Column(horizontalAlignment = Alignment.CenterHorizontally) { - component(appearance, shape) - Text( - text = shapeName, - fontSize = 12.sp, - modifier = Modifier.padding(top = 4.dp) - ) - } - } - } - Divider(modifier = Modifier.padding(top = 16.dp)) - } - } - } - } -} From 08ab910df441dc7fde280c2df16a51c72826e9f9 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 01:16:54 +0300 Subject: [PATCH 06/75] refactor(storybook): module structure --- mobile/kmp/.junie/guidelines.md | 63 +++++++++++++++++++ .../kotlin/com/atls/hyperion/sample/App.kt | 2 +- .../hyperion/storybook/config/Constants.kt | 5 ++ .../{ => fragments/storybook}/Storybook.kt | 8 ++- .../{ => fragments/storybook/ui}/Sidebar.kt | 20 +++--- .../{ => shared/model}/ComponentExample.kt | 2 +- .../{ => shared/ui}/ComponentVariants.kt | 20 +++--- .../storybook/shared/ui/theme/FontSize.kt | 9 +++ .../storybook/shared/ui/theme/Padding.kt | 10 +++ .../atls/hyperion/ui/theme/tokens/Spaces.kt | 1 + 10 files changed, 116 insertions(+), 24 deletions(-) create mode 100644 mobile/kmp/.junie/guidelines.md create mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/config/Constants.kt rename mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/{ => fragments/storybook}/Storybook.kt (91%) rename mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/{ => fragments/storybook/ui}/Sidebar.kt (78%) rename mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/{ => shared/model}/ComponentExample.kt (72%) rename mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/{ => shared/ui}/ComponentVariants.kt (75%) create mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/FontSize.kt create mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/Padding.kt diff --git a/mobile/kmp/.junie/guidelines.md b/mobile/kmp/.junie/guidelines.md new file mode 100644 index 000000000..2096c7be5 --- /dev/null +++ b/mobile/kmp/.junie/guidelines.md @@ -0,0 +1,63 @@ +# Project Guidelines + +## Scope +- Репозиторий — **многомодульный Android‑проект** на Kotlin. +- Цель изменений — расширение функциональности без нарушения существующих контрактов. +- Архитектура базируется на принципах **FSD (Feature‑Sliced Design)**, адаптированных под мобильную разработку. + +## Структура проекта +- Gradle multi‑module: `:app`, `:features:*`, `:ui`, `:shared`, `:navigation`. +- Build Tool: **Gradle 8+** с использованием **Kotlin DSL** (`build.gradle.kts`). +- Convention Plugins используются для переиспользования конфигураций, зависимостей и версий. + +## Архитектура +- **Feature‑Sliced Design (FSD)** + - Код во фичах делится на FSD‑слои: `screens` (Pages), `fragments` (Widgets/Features), `entities`, `shared`, `app`. + - **Screens**: основные пользовательские точки входа (экраны). + - **Fragments**: переиспользуемые UI‑блоки фичи (аналог Widget/Feature UI сегментов в FSD). + - **Entities**: модели, константы, API/мапперы, относящиеся к фиче. + - **Shared**: утилиты и ошибки, специфичные для фичи (shared‑код на уровне фичи). + - **App**: DI и навигация фичи. + - Зависимости строго направленные: `screens` → `fragments` → `entities` → `shared`. + - Нельзя делать циклические или горизонтальные импорты между фичами/срезами. +- **DI (Dependency Injection)**: строго через **Koin**. +- **Сетевой слой**: основа — **Apollo GraphQL**; REST допустим только для медиа или сторонних интеграций. +- **UI**: Jetpack Compose + +## Новые модули (Features) +- Каждый новый модуль в `features/` обязан: + - Иметь чёткую область ответственности. + - Следовать **FSD‑правилам** разделения на слои. + - Использовать существующие UI‑примитивы из `:ui` и `:shared-ui`. + - Подключаться в `settings.gradle.kts` или `gradleSettings/modules.gradle.kts` (если используется) через `:features:` + +## Тесты +- Используется **Kotlin tests** (`kotlin.test`) как основной фреймворк для модульных тестов в KMM/Kotlin. +- Покрытие рекомендуется для логики внутри фич. +- Перед финальной сборкой: + - Проект должен успешно собираться (`./gradlew assembleDebug` / `assembleRelease`). + - Все тесты должны проходить. + +## Code Style +- **Магические значения** выносить в константы (например, в `config/Constants.kt`). +- **Повторяющийся код** выносить в отдельные функции/методы. +- **Один класс/функция — один файл**; не держать несколько функций/классов в одном файле. +- **Плоские нейминги:** если путь уже содержит название фичи/контекста, **не дублировать его в имени файла**. + Например, `features/profile/fragments/editing/Fragment.kt` — файл просто `Fragment.kt`. +- **Не писать комментарии в коде.** +- **Логировать можно только при дебаге.** +- Строки должны быть в `strings.xml`. +- Цвета и шрифты должны браться строго из темы (`ui/theme/Theme.kt`). +- Имена файлов начинаются строго с большой буквы + +## Что запрещено +- Ломать публичные API существующих модулей. +- Добавлять тяжёлые зависимости без согласования. +- Игнорировать **FSD‑правила** зависимостей. +- Смешивать логику между модулями напрямую — использовать API. + +## Поведение Junie +1. **Анализ**: сначала изучить структуру аналогичных фич. +2. **Минимализм**: вносить только необходимые изменения. +3. **Аргументация**: объяснять архитектурные изменения. +4. **Тестирование**: после выполнения задачи собирать проект и прогонять тесты diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt index 552faf06e..b0a3004bd 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt @@ -2,7 +2,7 @@ package com.atls.hyperion.sample import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable -import com.atls.hyperion.storybook.Storybook +import com.atls.hyperion.storybook.fragments.storybook.Storybook import com.atls.hyperion.ui.components.button.stories.ButtonExample @Composable diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/config/Constants.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/config/Constants.kt new file mode 100644 index 000000000..edc7c2c79 --- /dev/null +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/config/Constants.kt @@ -0,0 +1,5 @@ +package com.atls.hyperion.storybook.config + +import androidx.compose.ui.unit.dp + +internal val sidebarWidth = 250.dp diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/fragments/storybook/Storybook.kt similarity index 91% rename from mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/fragments/storybook/Storybook.kt index 5dcb0b102..4963b0f49 100644 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/fragments/storybook/Storybook.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.storybook +package com.atls.hyperion.storybook.fragments.storybook import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.slideInHorizontally @@ -19,11 +19,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import com.atls.hyperion.storybook.fragments.storybook.ui.Sidebar import com.atls.hyperion.storybook.generated.resources.Res import com.atls.hyperion.storybook.generated.resources.menu import com.atls.hyperion.storybook.generated.resources.select_component_from_sidebar import com.atls.hyperion.storybook.generated.resources.toggle_sidebar +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.theme.Padding import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -45,7 +47,7 @@ fun Storybook( IconButton( onClick = { isSidebarVisible = !isSidebarVisible }, modifier = Modifier - .padding(12.dp) + .padding(Padding.small) ) { Icon( painter = painterResource(Res.drawable.menu), diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/fragments/storybook/ui/Sidebar.kt similarity index 78% rename from mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/fragments/storybook/ui/Sidebar.kt index c5b1e15a0..a754bde1a 100644 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/fragments/storybook/ui/Sidebar.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.storybook +package com.atls.hyperion.storybook.fragments.storybook.ui import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -17,10 +17,12 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp +import com.atls.hyperion.storybook.config.sidebarWidth import com.atls.hyperion.storybook.generated.resources.Res import com.atls.hyperion.storybook.generated.resources.components +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.theme.FontSize +import com.atls.hyperion.storybook.shared.ui.theme.Padding import org.jetbrains.compose.resources.stringResource @Composable @@ -38,19 +40,19 @@ fun Sidebar( Surface( modifier = Modifier .fillMaxHeight() - .width(250.dp), + .width(sidebarWidth), color = MaterialTheme.colors.surface ) { Column( modifier = Modifier .fillMaxSize() - .padding(14.dp) + .padding(Padding.medium) ) { Text( text = stringResource(Res.string.components), - fontSize = 20.sp, + fontSize = FontSize.large, fontWeight = FontWeight.Bold, - modifier = Modifier.padding(vertical = 24.dp) + modifier = Modifier.padding(vertical = Padding.large) ) LazyColumn { items(components) { component -> @@ -59,9 +61,9 @@ fun Sidebar( modifier = Modifier .fillMaxWidth() .clickable { onComponentClick(component) } - .padding(vertical = 12.dp), + .padding(vertical = Padding.small), fontWeight = if (component == selectedComponent) FontWeight.Bold else FontWeight.Normal, - fontSize = 16.sp + fontSize = FontSize.small ) Divider() } diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt similarity index 72% rename from mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt index ecc04bf45..9bd08f1de 100644 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.storybook +package com.atls.hyperion.storybook.shared.model import androidx.compose.runtime.Composable diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt similarity index 75% rename from mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt index de2e5163f..c0e6bb68b 100644 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.storybook +package com.atls.hyperion.storybook.shared.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -12,8 +12,8 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp +import com.atls.hyperion.storybook.shared.ui.theme.FontSize +import com.atls.hyperion.storybook.shared.ui.theme.Padding @Composable fun ComponentVariants( @@ -26,22 +26,22 @@ fun ComponentVariants( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(24.dp) + .padding(Padding.medium), + verticalArrangement = Arrangement.spacedBy(Padding.large) ) { Text( text = name, - fontSize = 24.sp, + fontSize = FontSize.large, fontWeight = FontWeight.Bold ) appearances.forEach { (appearanceName, appearanceProvider) -> Column( - verticalArrangement = Arrangement.spacedBy(16.dp) + verticalArrangement = Arrangement.spacedBy(Padding.medium), ) { Text( text = appearanceName, - fontSize = 20.sp, + fontSize = FontSize.medium, fontWeight = FontWeight.SemiBold ) @@ -52,8 +52,8 @@ fun ComponentVariants( ) { Text( text = shapeName, - fontSize = 16.sp, - modifier = Modifier.padding(top = 8.dp) + fontSize = FontSize.small, + modifier = Modifier.padding(top = Padding.tiny) ) content(appearanceProvider(), shapeProvider()) } diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/FontSize.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/FontSize.kt new file mode 100644 index 000000000..ce66f2e52 --- /dev/null +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/FontSize.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.storybook.shared.ui.theme + +import androidx.compose.ui.unit.sp + +object FontSize { + val large = 24.sp + val medium = 20.sp + val small = 12.sp +} diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/Padding.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/Padding.kt new file mode 100644 index 000000000..4aaa5e0b5 --- /dev/null +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/theme/Padding.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.storybook.shared.ui.theme + +import androidx.compose.ui.unit.dp + +object Padding { + val large = 24.dp + val medium = 16.dp + val small = 12.dp + val tiny = 8.dp +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Spaces.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Spaces.kt index 785872193..65d5f2bac 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Spaces.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Spaces.kt @@ -11,6 +11,7 @@ object Space { val g10 = 10.dp val g12 = 12.dp val g14 = 14.dp + val g16 = 16.dp val g17 = 17.dp val g22 = 22.dp val g24 = 24.dp From 5820544a7a1299471407f353735d3e2ff228d347 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 01:27:58 +0300 Subject: [PATCH 07/75] feat(theme): button component --- .../hyperion/ui/components/button/Button.kt | 37 ++++++ .../hyperion/ui/components/button/Layout.kt | 111 +++++++++++++++++ .../ui/components/button/locals/LocalState.kt | 8 ++ .../ui/components/button/state/ButtonState.kt | 7 ++ .../button/stories/ButtonExample.kt | 93 +++++++++++++++ .../button/styles/appearance/Appearance.kt | 23 ++++ .../button/styles/appearance/Variants.kt | 112 ++++++++++++++++++ .../button/styles/appearance/colors/Colors.kt | 22 ++++ .../components/button/styles/shape/Shape.kt | 14 +++ .../button/styles/shape/Variants.kt | 50 ++++++++ .../atls/hyperion/ui/shared/addon/Addon.kt | 11 ++ .../atls/hyperion/ui/shared/addon/Position.kt | 5 + .../atls/hyperion/ui/shared/addon/Scope.kt | 15 +++ .../hyperion/ui/shared/addon/SlotManager.kt | 7 ++ .../hyperion/ui/shared/addon/dsl/Build.kt | 9 ++ .../hyperion/ui/theme/tokens/Elevation.kt | 11 ++ 16 files changed, 535 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Button.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/locals/LocalState.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/colors/Colors.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Addon.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Position.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Scope.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/SlotManager.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/dsl/Build.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Button.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Button.kt new file mode 100644 index 000000000..748afb949 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Button.kt @@ -0,0 +1,37 @@ +package com.atls.hyperion.ui.components.button + +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import com.atls.hyperion.ui.components.button.locals.LocalState +import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance +import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape +import com.atls.hyperion.ui.shared.addon.AddonSlotManager + +@Composable +fun Button( + modifier: Modifier = Modifier, + text: String, + enabled: Boolean = true, + appearance: ButtonAppearance, + shape: ButtonShape, + addons: AddonSlotManager = AddonSlotManager(), + onClick: () -> Unit +) { + ButtonLayout( + modifier = modifier, + enabled = enabled, + appearance = appearance, + shape = shape, + addons = addons, + onClick = onClick + ) { + Text( + text = text, + textAlign = TextAlign.Center, + color = appearance.fromState(LocalState.current).textColor, + style = shape.typography + ) + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt new file mode 100644 index 000000000..d9e8dd38e --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt @@ -0,0 +1,111 @@ +package com.atls.hyperion.ui.components.button + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import com.atls.hyperion.ui.components.button.locals.LocalState +import com.atls.hyperion.ui.components.button.state.ButtonState +import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance +import com.atls.hyperion.ui.components.button.styles.appearance.colors.Colors +import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape +import com.atls.hyperion.ui.theme.properties.button.ButtonSize +import com.atls.hyperion.ui.theme.properties.shadow.Elevation +import com.atls.hyperion.ui.shared.addon.AddonPosition +import com.atls.hyperion.ui.shared.addon.AddonSlotManager + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ButtonLayout( + modifier: Modifier = Modifier, + enabled: Boolean = true, + appearance: ButtonAppearance, + shape: ButtonShape, + addons: AddonSlotManager = AddonSlotManager(), + onClick: () -> Unit, + content: @Composable () -> Unit +) { + val interactionSource = remember { MutableInteractionSource() } + val isPressed = interactionSource.collectIsPressedAsState().value + + val state = when { + !enabled -> ButtonState.Disabled + isPressed -> ButtonState.Pressed + else -> ButtonState.Default + } + val colors = appearance.fromState(state) + + CompositionLocalProvider( + LocalState provides state, + LocalMinimumInteractiveComponentEnforcement provides false + ) { + Button( + onClick = onClick, + shape = RoundedCornerShape(shape.cornerRadius), + colors = ButtonDefaults.buttonColors( + containerColor = when (colors) { + is Colors.Solid -> colors.backgroundColor + is Colors.Gradient -> Color.Transparent + }, + contentColor = colors.textColor, + disabledContainerColor = when (colors) { + is Colors.Solid -> colors.backgroundColor + is Colors.Gradient -> Color.Transparent + }, + disabledContentColor = colors.textColor + ), + border = BorderStroke(shape.borderStroke, colors.borderColor), + contentPadding = shape.paddings, + enabled = enabled, + elevation = ButtonDefaults.buttonElevation( + defaultElevation = Elevation.none, + pressedElevation = Elevation.none, + disabledElevation = Elevation.none + ), + interactionSource = interactionSource, + modifier = modifier + .defaultMinSize(ButtonSize.minWidth, ButtonSize.minHeight) + .shadow( + elevation = appearance.shadowElevation, + shape = RoundedCornerShape(shape.cornerRadius), + clip = false + ) + .then( + if (colors is Colors.Gradient) { + Modifier.background( + colors.backgroundBrush, + RoundedCornerShape(shape.cornerRadius) + ) + } else Modifier + ) + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + addons.get(AddonPosition.Before).forEach { + it.Content() + it.Spacer() + } + + content() + + addons.get(AddonPosition.After).forEach { + it.Spacer() + it.Content() + } + } + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/locals/LocalState.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/locals/LocalState.kt new file mode 100644 index 000000000..daf383b04 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/locals/LocalState.kt @@ -0,0 +1,8 @@ +package com.atls.hyperion.ui.components.button.locals + +import androidx.compose.runtime.compositionLocalOf +import com.atls.hyperion.ui.components.button.state.ButtonState + +val LocalState = compositionLocalOf { + error("ButtonState not provided") +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt new file mode 100644 index 000000000..d555822b7 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt @@ -0,0 +1,7 @@ +package com.atls.hyperion.ui.components.button.state + +sealed interface ButtonState { + object Default : ButtonState + object Disabled : ButtonState + object Pressed : ButtonState +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt new file mode 100644 index 000000000..4229c35aa --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt @@ -0,0 +1,93 @@ +package com.atls.hyperion.ui.components.button.stories + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.dp +import com.atls.hyperion.ui.components.button.Button +import com.atls.hyperion.ui.components.button.style.appearance.ButtonAppearance +import com.atls.hyperion.ui.components.button.style.appearance.ButtonAppearanceColors +import com.atls.hyperion.ui.components.button.style.shape.ButtonShape +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.theme.tokens.colors.Colors + +class ButtonExample : ComponentExample { + override val name: String = "Button" + + @Composable + override fun Content() { + ComponentVariants( + name = "Button", + appearances = listOf( + "Primary Blue" to { primaryAppearance() }, + "Light Blue" to { lightBlueAppearance() } + ), + shapes = listOf( + "Large" to { largeShape() }, + "Medium" to { mediumShape() } + ) + ) { appearance: ButtonAppearance, shape: ButtonShape -> + Button( + text = "Button", + appearance = appearance, + shape = shape, + onClick = {} + ) + } + } +} + +@Composable +private fun primaryAppearance() = ButtonAppearance( + default = ButtonAppearanceColors( + backgroundColor = Colors.Button.Blue.Default.background, + textColor = Colors.Button.Blue.Default.font, + borderColor = Colors.Button.Blue.Default.border + ), + pressed = ButtonAppearanceColors( + backgroundColor = Colors.Button.Blue.Pressed.background, + textColor = Colors.Button.Blue.Pressed.font, + borderColor = Colors.Button.Blue.Pressed.border + ), + disabled = ButtonAppearanceColors( + backgroundColor = Colors.Button.Blue.Disabled.background, + textColor = Colors.Button.Blue.Disabled.font, + borderColor = Colors.Button.Blue.Disabled.border + ) +) + +@Composable +private fun lightBlueAppearance() = ButtonAppearance( + default = ButtonAppearanceColors( + backgroundColor = Colors.Button.LightBlue.Default.background, + textColor = Colors.Button.LightBlue.Default.font, + borderColor = Colors.Button.LightBlue.Default.border + ), + pressed = ButtonAppearanceColors( + backgroundColor = Colors.Button.LightBlue.Pressed.background, + textColor = Colors.Button.LightBlue.Pressed.font, + borderColor = Colors.Button.LightBlue.Pressed.border + ), + disabled = ButtonAppearanceColors( + backgroundColor = Colors.Button.LightBlue.Disabled.background, + textColor = Colors.Button.LightBlue.Disabled.font, + borderColor = Colors.Button.LightBlue.Disabled.border + ) +) + +@Composable +private fun largeShape() = ButtonShape( + cornerRadius = 8.dp, + paddings = PaddingValues(16.dp, 12.dp), + typography = TextStyle(), + borderStroke = 1.dp +) + +@Composable +private fun mediumShape() = ButtonShape( + cornerRadius = 4.dp, + paddings = PaddingValues(12.dp, 8.dp), + typography = TextStyle(), + borderStroke = 1.dp +) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt new file mode 100644 index 000000000..62336e13e --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt @@ -0,0 +1,23 @@ +package com.atls.hyperion.ui.components.button.styles.appearance + +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.components.button.state.ButtonState +import com.atls.hyperion.ui.components.button.styles.appearance.colors.Colors +import com.atls.hyperion.ui.theme.tokens.Elevation + +data class ButtonAppearance( + val default: Colors, + val pressed: Colors, + val disabled: Colors, + val shadowElevation: Dp = Elevation.none +) { + fun fromState(state: ButtonState): Colors { + return when (state) { + ButtonState.Default -> default + ButtonState.Disabled -> disabled + ButtonState.Pressed -> pressed + } + } + + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt new file mode 100644 index 000000000..c4ac2edd6 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt @@ -0,0 +1,112 @@ +package com.atls.hyperion.ui.components.button.styles.appearance + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.components.button.styles.appearance.colors.Colors +import com.atls.hyperion.ui.theme.Theme +import com.atls.hyperion.ui.theme.properties.shadow.Elevation + +@Composable +fun ButtonAppearance.Companion.primary(): ButtonAppearance = + ButtonAppearance( + default = Colors.Solid( + backgroundColor = Theme.button.primary, + textColor = Theme.button.textPrimary + ), + pressed = Colors.Solid( + backgroundColor = Theme.button.primaryFocus, + textColor = Theme.button.textPrimaryFocus + ), + disabled = Colors.Solid( + backgroundColor = Theme.button.primaryDisabled, + textColor = Theme.button.textPrimaryDisabled + ) + ) + +@Composable +fun ButtonAppearance.Companion.secondary(): ButtonAppearance = + ButtonAppearance( + default = Colors.Solid( + backgroundColor = Theme.button.secondary, + textColor = Theme.text.secondary + ), + pressed = Colors.Solid( + backgroundColor = Theme.button.secondary, + textColor = Theme.button.textSecondaryFocus + ), + disabled = Colors.Solid( + backgroundColor = Theme.button.secondaryDisabled, + textColor = Theme.button.textSecondaryDisabled + ) + ) + + +@Composable +fun ButtonAppearance.Companion.ghost(): ButtonAppearance = + ButtonAppearance( + default = Colors.Solid( + backgroundColor = Theme.main.transparent, + textColor = Theme.text.secondary + ), + pressed = Colors.Solid( + backgroundColor = Theme.button.secondary, + textColor = Theme.button.textSecondaryFocus + ), + disabled = Colors.Solid( + backgroundColor = Theme.button.secondaryDisabled, + textColor = Theme.button.textSecondaryDisabled + ) + ) + +@Composable +fun ButtonAppearance.Companion.gradient(): ButtonAppearance = + ButtonAppearance( + default = Colors.Gradient( + backgroundBrush = Theme.button.backgroundGradient, + textColor = Theme.button.textPrimary, + ), + pressed = Colors.Gradient( + backgroundBrush = Theme.button.backgroundGradient, + textColor = Theme.button.textPrimaryFocus + ), + disabled = Colors.Gradient( + backgroundBrush = Theme.button.backgroundGradientDisabled, + textColor = Theme.button.textPrimary + ), + shadowElevation = Elevation.tiny + ) + +@Composable +fun ButtonAppearance.Companion.light(): ButtonAppearance = + ButtonAppearance( + default = Colors.Solid( + backgroundColor = Theme.contrastInverted.low, + textColor = Theme.button.textPrimary + ), + pressed = Colors.Solid( + backgroundColor = Theme.button.secondary, + textColor = Theme.button.textPrimaryFocus, + borderColor = Theme.contrastInverted.lower + ), + disabled = Colors.Solid( + backgroundColor = Theme.button.secondaryDisabled, + textColor = Theme.button.textPrimaryDisabled + ) + ) + +@Composable +fun ButtonAppearance.Companion.activity(): ButtonAppearance = + ButtonAppearance( + default = Colors.Solid( + backgroundColor = Theme.button.activity, + textColor = Theme.icon.link + ), + pressed = Colors.Solid( + backgroundColor = Theme.main.primary, + textColor = Theme.icon.invertedMain + ), + disabled = Colors.Solid( + backgroundColor = Theme.button.activity, + textColor = Theme.icon.link + ) + ) + diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/colors/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/colors/Colors.kt new file mode 100644 index 000000000..981372e4d --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/colors/Colors.kt @@ -0,0 +1,22 @@ +package com.atls.hyperion.ui.components.button.styles.appearance.colors + +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color + +sealed class Colors( + val textColor: Color, + val borderColor: Color = Color.Transparent +) { + class Solid( + val backgroundColor: Color, + textColor: Color, + borderColor: Color = Color.Transparent + ) : Colors(textColor, borderColor) + + class Gradient( + val backgroundBrush: Brush, + textColor: Color, + borderColor: Color = Color.Transparent + ) : Colors(textColor, borderColor) +} + diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Shape.kt new file mode 100644 index 000000000..5b4a745a3 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Shape.kt @@ -0,0 +1,14 @@ +package com.atls.hyperion.ui.components.button.styles.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp + +data class ButtonShape( + val cornerRadius: Dp, + val paddings: PaddingValues, + val typography: TextStyle, + val borderStroke: Dp +) { + companion object Companion +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt new file mode 100644 index 000000000..a943d29c5 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt @@ -0,0 +1,50 @@ +package com.atls.hyperion.ui.components.button.styles.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.Theme +import com.atls.hyperion.ui.theme.properties.BorderStroke +import com.atls.hyperion.ui.theme.properties.CornerRadius +import com.atls.hyperion.ui.theme.properties.Padding + +@Composable +fun ButtonShape.Companion.large(): ButtonShape = + ButtonShape( + cornerRadius = CornerRadius.regular, + paddings = PaddingValues( + horizontal = Padding.semiLarge, + vertical = Padding.small + ), + typography = Theme.typography.body.regular.large, + borderStroke = BorderStroke.tiny + ) + +@Composable +fun ButtonShape.Companion.default(): ButtonShape = + ButtonShape( + cornerRadius = CornerRadius.small, + paddings = PaddingValues( + horizontal = Padding.medium, + vertical = Padding.xsmall + ), + typography = Theme.typography.caption.regular.large, + borderStroke = BorderStroke.tiny + ) + +@Composable +fun ButtonShape.Companion.rounded(): ButtonShape = + ButtonShape( + cornerRadius = CornerRadius.full, + paddings = PaddingValues(Padding.xsmall), + typography = Theme.typography.caption.regular.large, + borderStroke = BorderStroke.none + ) + +@Composable +fun ButtonShape.Companion.activity(): ButtonShape = + ButtonShape( + cornerRadius = CornerRadius.medium, + paddings = PaddingValues(Padding.medium), + typography = Theme.typography.body.regular.medium, + borderStroke = BorderStroke.none + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Addon.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Addon.kt new file mode 100644 index 000000000..bb11c1777 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Addon.kt @@ -0,0 +1,11 @@ +package com.atls.hyperion.ui.shared.addon + +import androidx.compose.runtime.Composable + +interface Addon { + @Composable + fun Content() + + @Composable + fun Spacer() +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Position.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Position.kt new file mode 100644 index 000000000..b856469cb --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Position.kt @@ -0,0 +1,5 @@ +package com.atls.hyperion.ui.shared.addon + +enum class AddonPosition { + Before, After +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Scope.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Scope.kt new file mode 100644 index 000000000..8ba6412ed --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/Scope.kt @@ -0,0 +1,15 @@ +package com.atls.hyperion.ui.shared.addon + +class AddonScope { + private val slots = mutableMapOf>() + + fun before(vararg addons: Addon) { + slots.getOrPut(AddonPosition.Before) { mutableListOf() }.addAll(addons) + } + + fun after(vararg addons: Addon) { + slots.getOrPut(AddonPosition.After) { mutableListOf() }.addAll(addons) + } + + fun build() = AddonSlotManager(slots) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/SlotManager.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/SlotManager.kt new file mode 100644 index 000000000..be5ea8d68 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/SlotManager.kt @@ -0,0 +1,7 @@ +package com.atls.hyperion.ui.shared.addon + +data class AddonSlotManager( + val addons: Map> = emptyMap() +) { + fun get(position: AddonPosition): List = addons[position].orEmpty() +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/dsl/Build.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/dsl/Build.kt new file mode 100644 index 000000000..aee2a56f4 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/addon/dsl/Build.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.shared.addon.dsl + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.shared.addon.AddonScope +import com.atls.hyperion.ui.shared.addon.AddonSlotManager + +@Composable +fun build(builder: @Composable AddonScope.() -> Unit): AddonSlotManager = + AddonScope().apply { builder() }.build() diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt new file mode 100644 index 000000000..25397c47e --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt @@ -0,0 +1,11 @@ +package com.atls.hyperion.ui.theme.tokens + +import androidx.compose.ui.unit.dp + +object Elevation { + val none = 0.dp + val micro = 2.dp + val tiny = 6.dp + val small = 12.dp + val large = 20.dp +} From d66e606ef9b13378e9b59303a1be807cb0093eb3 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 00:26:19 +0300 Subject: [PATCH 08/75] feat(common): storybook resources --- .../sample/src/commonMain/composeResources/drawable/menu.xml | 5 +++++ .../src/commonMain/composeResources/values/strings.xml | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml create mode 100644 mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml diff --git a/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml b/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml new file mode 100644 index 000000000..9e7f0e919 --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml b/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 000000000..c2e3d112a --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,5 @@ + + Components + Select a component from the sidebar + Toggle Sidebar + From 2680693313395a33a881d9c49dd79b959c67f8c8 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 00:26:31 +0300 Subject: [PATCH 09/75] feat(app): storybook sidebar --- .../atls/hyperion/sample/storybook/Sidebar.kt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt new file mode 100644 index 000000000..9c8fc0fd3 --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt @@ -0,0 +1,74 @@ +package com.atls.hyperion.sample.storybook + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Divider +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.atls.hyperion.ui.shared.stories.ComponentExample +import com.atls.hyperion.ui.theme.tokens.Space +import com.atls.hyperion.ui.theme.typography.FontSize +import hyperion.sample.generated.resources.Res +import hyperion.sample.generated.resources.components +import org.jetbrains.compose.resources.stringResource + +@Composable +fun Sidebar( + components: List, + selectedComponent: ComponentExample?, + onComponentClick: (ComponentExample) -> Unit, + onClose: () -> Unit +) { + Box( + modifier = Modifier + .fillMaxSize() + .clickable { onClose() } + ) { + Surface( + modifier = Modifier + .fillMaxHeight() + .width(250.dp), + color = MaterialTheme.colors.surface + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(Space.g14) + ) { + Text( + text = stringResource(Res.string.components), + fontSize = FontSize.large, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(vertical = Space.g24) + ) + LazyColumn { + items(components) { component -> + Text( + text = component.name, + modifier = Modifier + .fillMaxWidth() + .clickable { onComponentClick(component) } + .padding(vertical = Space.g12), + fontWeight = if (component == selectedComponent) FontWeight.Bold else FontWeight.Normal, + fontSize = FontSize.medium + ) + Divider() + } + } + } + } + } +} From ab697e4b553a037a8400e1b740273ff6b4b636f3 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 00:26:38 +0300 Subject: [PATCH 10/75] feat(app): storybook component --- .../hyperion/sample/storybook/Storybook.kt | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt new file mode 100644 index 000000000..3cd112f85 --- /dev/null +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt @@ -0,0 +1,89 @@ +package com.atls.hyperion.sample.storybook + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.shared.stories.ComponentExample +import com.atls.hyperion.ui.theme.tokens.Space +import hyperion.sample.generated.resources.Res +import hyperion.sample.generated.resources.menu +import hyperion.sample.generated.resources.select_component_from_sidebar +import hyperion.sample.generated.resources.toggle_sidebar +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource + +@Composable +fun Storybook( + components: List +) { + var isSidebarVisible by remember { mutableStateOf(false) } + var selectedComponent by remember(components) { + mutableStateOf(components.firstOrNull()) + } + + Box { + Column( + modifier = Modifier + .fillMaxSize() + .safeDrawingPadding() + ) { + IconButton( + onClick = { isSidebarVisible = !isSidebarVisible }, + modifier = Modifier + .padding(Space.g12) + ) { + Icon( + painter = painterResource(Res.drawable.menu), + contentDescription = stringResource(Res.string.toggle_sidebar), + tint = MaterialTheme.colors.onSurface + ) + } + Box( + modifier = Modifier + .fillMaxSize() + ) { + if (selectedComponent != null) { + selectedComponent?.Content() + } else { + Text( + text = stringResource(Res.string.select_component_from_sidebar), + modifier = Modifier + .align(Alignment.Center), + ) + } + } + } + + AnimatedVisibility( + visible = isSidebarVisible, + enter = slideInHorizontally(), + exit = slideOutHorizontally() + ) { + Sidebar( + components = components, + selectedComponent = selectedComponent, + onComponentClick = { component -> + selectedComponent = component + isSidebarVisible = false + }, + onClose = { isSidebarVisible = false } + ) + } + } +} From a01e1dc0bb2d81011b7982efdd3af86c12dced67 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 01:04:26 +0300 Subject: [PATCH 11/75] refactor(common): extract storybook to separate module --- .../composeResources/drawable/menu.xml | 5 -- .../composeResources/values/strings.xml | 5 -- .../kotlin/com/atls/hyperion/sample/App.kt | 2 +- .../hyperion/storybook/ComponentExample.kt | 13 ++++ .../hyperion/storybook/ComponentVariants.kt | 65 +++++++++++++++++++ .../com/atls/hyperion}/storybook/Sidebar.kt | 20 +++--- .../com/atls/hyperion}/storybook/Storybook.kt | 15 ++--- .../shared/model/ComponentExample.kt | 9 --- 8 files changed, 95 insertions(+), 39 deletions(-) delete mode 100644 mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml delete mode 100644 mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml create mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt create mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt rename mobile/kmp/{sample/src/commonMain/kotlin/com/atls/hyperion/sample => storybook/src/commonMain/kotlin/com/atls/hyperion}/storybook/Sidebar.kt (79%) rename mobile/kmp/{sample/src/commonMain/kotlin/com/atls/hyperion/sample => storybook/src/commonMain/kotlin/com/atls/hyperion}/storybook/Storybook.kt (87%) delete mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt diff --git a/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml b/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml deleted file mode 100644 index 9e7f0e919..000000000 --- a/mobile/kmp/sample/src/commonMain/composeResources/drawable/menu.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml b/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml deleted file mode 100644 index c2e3d112a..000000000 --- a/mobile/kmp/sample/src/commonMain/composeResources/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - Components - Select a component from the sidebar - Toggle Sidebar - diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt index b0a3004bd..552faf06e 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt @@ -2,7 +2,7 @@ package com.atls.hyperion.sample import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable -import com.atls.hyperion.storybook.fragments.storybook.Storybook +import com.atls.hyperion.storybook.Storybook import com.atls.hyperion.ui.components.button.stories.ButtonExample @Composable diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt new file mode 100644 index 000000000..93767f8fa --- /dev/null +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt @@ -0,0 +1,13 @@ +<<<<<<<< HEAD:mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt +package com.atls.hyperion.storybook.shared.model +======== +package com.atls.hyperion.storybook +>>>>>>>> c54afd81 (refactor(common): extract storybook to separate module):mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt + +import androidx.compose.runtime.Composable + +interface ComponentExample { + val name: String + @Composable + fun Content() +} diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt new file mode 100644 index 000000000..de2e5163f --- /dev/null +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt @@ -0,0 +1,65 @@ +package com.atls.hyperion.storybook + +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.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun ComponentVariants( + name: String, + appearances: List A>>, + shapes: List S>>, + content: @Composable (A, S) -> Unit +) { + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + Text( + text = name, + fontSize = 24.sp, + fontWeight = FontWeight.Bold + ) + + appearances.forEach { (appearanceName, appearanceProvider) -> + Column( + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text( + text = appearanceName, + fontSize = 20.sp, + fontWeight = FontWeight.SemiBold + ) + + shapes.forEach { (shapeName, shapeProvider) -> + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = shapeName, + fontSize = 16.sp, + modifier = Modifier.padding(top = 8.dp) + ) + content(appearanceProvider(), shapeProvider()) + } + Divider() + } + } + } + } +} diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt similarity index 79% rename from mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt index 9c8fc0fd3..c5b1e15a0 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Sidebar.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.sample.storybook +package com.atls.hyperion.storybook import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -18,11 +18,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.atls.hyperion.ui.shared.stories.ComponentExample -import com.atls.hyperion.ui.theme.tokens.Space -import com.atls.hyperion.ui.theme.typography.FontSize -import hyperion.sample.generated.resources.Res -import hyperion.sample.generated.resources.components +import androidx.compose.ui.unit.sp +import com.atls.hyperion.storybook.generated.resources.Res +import com.atls.hyperion.storybook.generated.resources.components import org.jetbrains.compose.resources.stringResource @Composable @@ -46,13 +44,13 @@ fun Sidebar( Column( modifier = Modifier .fillMaxSize() - .padding(Space.g14) + .padding(14.dp) ) { Text( text = stringResource(Res.string.components), - fontSize = FontSize.large, + fontSize = 20.sp, fontWeight = FontWeight.Bold, - modifier = Modifier.padding(vertical = Space.g24) + modifier = Modifier.padding(vertical = 24.dp) ) LazyColumn { items(components) { component -> @@ -61,9 +59,9 @@ fun Sidebar( modifier = Modifier .fillMaxWidth() .clickable { onComponentClick(component) } - .padding(vertical = Space.g12), + .padding(vertical = 12.dp), fontWeight = if (component == selectedComponent) FontWeight.Bold else FontWeight.Normal, - fontSize = FontSize.medium + fontSize = 16.sp ) Divider() } diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt similarity index 87% rename from mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt rename to mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt index 3cd112f85..5dcb0b102 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/storybook/Storybook.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.sample.storybook +package com.atls.hyperion.storybook import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.slideInHorizontally @@ -19,12 +19,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import com.atls.hyperion.ui.shared.stories.ComponentExample -import com.atls.hyperion.ui.theme.tokens.Space -import hyperion.sample.generated.resources.Res -import hyperion.sample.generated.resources.menu -import hyperion.sample.generated.resources.select_component_from_sidebar -import hyperion.sample.generated.resources.toggle_sidebar +import androidx.compose.ui.unit.dp +import com.atls.hyperion.storybook.generated.resources.Res +import com.atls.hyperion.storybook.generated.resources.menu +import com.atls.hyperion.storybook.generated.resources.select_component_from_sidebar +import com.atls.hyperion.storybook.generated.resources.toggle_sidebar import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -46,7 +45,7 @@ fun Storybook( IconButton( onClick = { isSidebarVisible = !isSidebarVisible }, modifier = Modifier - .padding(Space.g12) + .padding(12.dp) ) { Icon( painter = painterResource(Res.drawable.menu), diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt deleted file mode 100644 index 9bd08f1de..000000000 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.atls.hyperion.storybook.shared.model - -import androidx.compose.runtime.Composable - -interface ComponentExample { - val name: String - @Composable - fun Content() -} From 11b4d5c79d63cf30f1eb701ee572ba2c4d3bc676 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 01:16:54 +0300 Subject: [PATCH 12/75] refactor(storybook): module structure --- .../kotlin/com/atls/hyperion/sample/App.kt | 2 +- .../hyperion/storybook/ComponentExample.kt | 13 --- .../hyperion/storybook/ComponentVariants.kt | 65 -------------- .../com/atls/hyperion/storybook/Sidebar.kt | 72 --------------- .../com/atls/hyperion/storybook/Storybook.kt | 88 ------------------- .../shared/model/ComponentExample.kt | 9 ++ 6 files changed, 10 insertions(+), 239 deletions(-) delete mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt delete mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt delete mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt delete mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt create mode 100644 mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt index 552faf06e..b0a3004bd 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt @@ -2,7 +2,7 @@ package com.atls.hyperion.sample import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable -import com.atls.hyperion.storybook.Storybook +import com.atls.hyperion.storybook.fragments.storybook.Storybook import com.atls.hyperion.ui.components.button.stories.ButtonExample @Composable diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt deleted file mode 100644 index 93767f8fa..000000000 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt +++ /dev/null @@ -1,13 +0,0 @@ -<<<<<<<< HEAD:mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt -package com.atls.hyperion.storybook.shared.model -======== -package com.atls.hyperion.storybook ->>>>>>>> c54afd81 (refactor(common): extract storybook to separate module):mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentExample.kt - -import androidx.compose.runtime.Composable - -interface ComponentExample { - val name: String - @Composable - fun Content() -} diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt deleted file mode 100644 index de2e5163f..000000000 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/ComponentVariants.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.atls.hyperion.storybook - -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.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Divider -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp - -@Composable -fun ComponentVariants( - name: String, - appearances: List A>>, - shapes: List S>>, - content: @Composable (A, S) -> Unit -) { - Column( - modifier = Modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()) - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(24.dp) - ) { - Text( - text = name, - fontSize = 24.sp, - fontWeight = FontWeight.Bold - ) - - appearances.forEach { (appearanceName, appearanceProvider) -> - Column( - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - Text( - text = appearanceName, - fontSize = 20.sp, - fontWeight = FontWeight.SemiBold - ) - - shapes.forEach { (shapeName, shapeProvider) -> - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween - ) { - Text( - text = shapeName, - fontSize = 16.sp, - modifier = Modifier.padding(top = 8.dp) - ) - content(appearanceProvider(), shapeProvider()) - } - Divider() - } - } - } - } -} diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt deleted file mode 100644 index c5b1e15a0..000000000 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Sidebar.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.atls.hyperion.storybook - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material.Divider -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.atls.hyperion.storybook.generated.resources.Res -import com.atls.hyperion.storybook.generated.resources.components -import org.jetbrains.compose.resources.stringResource - -@Composable -fun Sidebar( - components: List, - selectedComponent: ComponentExample?, - onComponentClick: (ComponentExample) -> Unit, - onClose: () -> Unit -) { - Box( - modifier = Modifier - .fillMaxSize() - .clickable { onClose() } - ) { - Surface( - modifier = Modifier - .fillMaxHeight() - .width(250.dp), - color = MaterialTheme.colors.surface - ) { - Column( - modifier = Modifier - .fillMaxSize() - .padding(14.dp) - ) { - Text( - text = stringResource(Res.string.components), - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(vertical = 24.dp) - ) - LazyColumn { - items(components) { component -> - Text( - text = component.name, - modifier = Modifier - .fillMaxWidth() - .clickable { onComponentClick(component) } - .padding(vertical = 12.dp), - fontWeight = if (component == selectedComponent) FontWeight.Bold else FontWeight.Normal, - fontSize = 16.sp - ) - Divider() - } - } - } - } - } -} diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt deleted file mode 100644 index 5dcb0b102..000000000 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/Storybook.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.atls.hyperion.storybook - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.slideInHorizontally -import androidx.compose.animation.slideOutHorizontally -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawingPadding -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import com.atls.hyperion.storybook.generated.resources.Res -import com.atls.hyperion.storybook.generated.resources.menu -import com.atls.hyperion.storybook.generated.resources.select_component_from_sidebar -import com.atls.hyperion.storybook.generated.resources.toggle_sidebar -import org.jetbrains.compose.resources.painterResource -import org.jetbrains.compose.resources.stringResource - -@Composable -fun Storybook( - components: List -) { - var isSidebarVisible by remember { mutableStateOf(false) } - var selectedComponent by remember(components) { - mutableStateOf(components.firstOrNull()) - } - - Box { - Column( - modifier = Modifier - .fillMaxSize() - .safeDrawingPadding() - ) { - IconButton( - onClick = { isSidebarVisible = !isSidebarVisible }, - modifier = Modifier - .padding(12.dp) - ) { - Icon( - painter = painterResource(Res.drawable.menu), - contentDescription = stringResource(Res.string.toggle_sidebar), - tint = MaterialTheme.colors.onSurface - ) - } - Box( - modifier = Modifier - .fillMaxSize() - ) { - if (selectedComponent != null) { - selectedComponent?.Content() - } else { - Text( - text = stringResource(Res.string.select_component_from_sidebar), - modifier = Modifier - .align(Alignment.Center), - ) - } - } - } - - AnimatedVisibility( - visible = isSidebarVisible, - enter = slideInHorizontally(), - exit = slideOutHorizontally() - ) { - Sidebar( - components = components, - selectedComponent = selectedComponent, - onComponentClick = { component -> - selectedComponent = component - isSidebarVisible = false - }, - onClose = { isSidebarVisible = false } - ) - } - } -} diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt new file mode 100644 index 000000000..9bd08f1de --- /dev/null +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/model/ComponentExample.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.storybook.shared.model + +import androidx.compose.runtime.Composable + +interface ComponentExample { + val name: String + @Composable + fun Content() +} From 23d8f2d5b31d7c7d10be4522f1fb4673f916baad Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 02:29:15 +0300 Subject: [PATCH 13/75] refactor(button): state as enum --- .../hyperion/ui/components/button/state/ButtonState.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt index d555822b7..2f1d9a198 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/state/ButtonState.kt @@ -1,7 +1,7 @@ package com.atls.hyperion.ui.components.button.state -sealed interface ButtonState { - object Default : ButtonState - object Disabled : ButtonState - object Pressed : ButtonState +enum class ButtonState { + Default, + Disabled, + Pressed } From 415356a673772df70faea597e28710bb346f83e9 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 02:29:37 +0300 Subject: [PATCH 14/75] refactor(button): appearance colors --- .../components/button/styles/appearance/{colors => }/Colors.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/{colors => }/Colors.kt (98%) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/colors/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Colors.kt similarity index 98% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/colors/Colors.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Colors.kt index 981372e4d..ff1a1719d 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/colors/Colors.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Colors.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.components.button.styles.appearance.colors +package com.atls.hyperion.ui.components.button.styles.appearance import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color @@ -19,4 +19,3 @@ sealed class Colors( borderColor: Color = Color.Transparent ) : Colors(textColor, borderColor) } - From 4f6410341275cc53f03f76ce2ffd854f3e704c87 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 02:30:36 +0300 Subject: [PATCH 15/75] feat(button): story --- .../ui/components/button/stories/Component.kt | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt new file mode 100644 index 000000000..633bb3a69 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt @@ -0,0 +1,78 @@ +package com.atls.hyperion.ui.components.button.stories + +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.material.Switch +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.components.button.Button +import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance +import com.atls.hyperion.ui.components.button.styles.appearance.blue +import com.atls.hyperion.ui.components.button.styles.appearance.lightBlue +import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape +import com.atls.hyperion.ui.components.button.styles.shape.huge +import com.atls.hyperion.ui.components.button.styles.shape.large +import com.atls.hyperion.ui.components.button.styles.shape.medium +import com.atls.hyperion.ui.components.button.styles.shape.normal +import com.atls.hyperion.ui.components.button.styles.shape.semiMedium +import com.atls.hyperion.ui.components.button.styles.shape.small +import com.atls.hyperion.ui.components.button.styles.shape.smallSizeMediumRadii +import com.atls.hyperion.ui.primitives.HorizontalSpacer +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.layout.Space + +class ButtonStory : ComponentExample { + override val name: String = "Button" + + @Composable + override fun Content() { + var enabled by remember { mutableStateOf(true) } + + Column { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = Space.g12) + ) { + Text(modifier = Modifier.weight(1f), text = "Enabled") + HorizontalSpacer(Space.g12) + Switch(checked = enabled, onCheckedChange = { enabled = it }) + } + VerticalSpacer(Space.g12) + + ComponentVariants( + name = "Button", + appearances = listOf( + "Blue" to { ButtonAppearance.blue() }, + "Light Blue" to { ButtonAppearance.lightBlue() } + ), + shapes = listOf( + "Huge" to { ButtonShape.huge() }, + "Large" to { ButtonShape.large() }, + "Semi Medium" to { ButtonShape.semiMedium() }, + "Medium" to { ButtonShape.medium() }, + "Normal" to { ButtonShape.normal() }, + "Small" to { ButtonShape.small() }, + "Small Medium Radii" to { ButtonShape.smallSizeMediumRadii() } + ) + ) { appearance: ButtonAppearance, shape: ButtonShape -> + Button( + text = "Button", + appearance = appearance, + shape = shape, + enabled = enabled, + onClick = {} + ) + } + } + } +} From 88ac576308da3b33b8a13b7a22c9b1b53da2652a Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 02:30:54 +0300 Subject: [PATCH 16/75] feat(theme): spacers --- .../com/atls/hyperion/ui/primitives/Spacer.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Spacer.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Spacer.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Spacer.kt new file mode 100644 index 000000000..5076d045f --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Spacer.kt @@ -0,0 +1,18 @@ +package com.atls.hyperion.ui.primitives + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp + +@Composable +fun VerticalSpacer(height: Dp) { + Spacer(Modifier.height(height)) +} + +@Composable +fun HorizontalSpacer(width: Dp) { + Spacer(Modifier.width(width)) +} From ce06810f7f4664c98d5e19ba4f9906d51746edd3 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 02:31:18 +0300 Subject: [PATCH 17/75] chore(theme): remove unused elevation --- .../ui/components/button/styles/appearance/Appearance.kt | 3 +-- .../kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt index 62336e13e..5a2048b9e 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt @@ -2,14 +2,13 @@ package com.atls.hyperion.ui.components.button.styles.appearance import androidx.compose.ui.unit.Dp import com.atls.hyperion.ui.components.button.state.ButtonState -import com.atls.hyperion.ui.components.button.styles.appearance.colors.Colors import com.atls.hyperion.ui.theme.tokens.Elevation data class ButtonAppearance( val default: Colors, val pressed: Colors, val disabled: Colors, - val shadowElevation: Dp = Elevation.none + val shadowElevation: Dp = Elevation.zero ) { fun fromState(state: ButtonState): Colors { return when (state) { diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt index 25397c47e..ff5674e06 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt @@ -3,9 +3,5 @@ package com.atls.hyperion.ui.theme.tokens import androidx.compose.ui.unit.dp object Elevation { - val none = 0.dp - val micro = 2.dp - val tiny = 6.dp - val small = 12.dp - val large = 20.dp + val zero = 0.dp } From 7d8127718d4a00c712b08f2e677ad74f2273d4a4 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 02:31:46 +0300 Subject: [PATCH 18/75] chore(theme): none border stroke --- .../kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt index c1fb5510a..2fb4e1852 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt @@ -5,7 +5,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp object Border { - val none: BorderStroke? = null + val none: BorderStroke = BorderStroke(0.dp, Color.Transparent) val thinLightBlue = BorderStroke(0.5.dp, Color(0xFFD2DDF9)) val thinLightGray = BorderStroke(0.5.dp, Color(0xFFE4E4E4)) val normalGray = BorderStroke(1.dp, Color(0xFF727272)) From 858508f4669a8c2374c5e993f78a7f9fa308f752 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 02:32:26 +0300 Subject: [PATCH 19/75] feat(button): styles --- .../hyperion/ui/components/button/Layout.kt | 29 ++-- .../button/stories/ButtonExample.kt | 93 ------------ .../button/styles/appearance/Variants.kt | 134 +++++------------- .../button/styles/shape/Variants.kt | 81 +++++++---- .../hyperion/ui/theme/tokens/layout/Spaces.kt | 1 + 5 files changed, 98 insertions(+), 240 deletions(-) delete mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt index d9e8dd38e..150e7c267 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt @@ -5,12 +5,11 @@ import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.LocalMinimumInteractiveComponentEnforcement import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember @@ -21,14 +20,13 @@ import androidx.compose.ui.graphics.Color import com.atls.hyperion.ui.components.button.locals.LocalState import com.atls.hyperion.ui.components.button.state.ButtonState import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance -import com.atls.hyperion.ui.components.button.styles.appearance.colors.Colors +import com.atls.hyperion.ui.components.button.styles.appearance.Colors import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape -import com.atls.hyperion.ui.theme.properties.button.ButtonSize -import com.atls.hyperion.ui.theme.properties.shadow.Elevation import com.atls.hyperion.ui.shared.addon.AddonPosition import com.atls.hyperion.ui.shared.addon.AddonSlotManager +import com.atls.hyperion.ui.theme.tokens.Elevation -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterialApi::class) @Composable fun ButtonLayout( modifier: Modifier = Modifier, @@ -57,12 +55,12 @@ fun ButtonLayout( onClick = onClick, shape = RoundedCornerShape(shape.cornerRadius), colors = ButtonDefaults.buttonColors( - containerColor = when (colors) { + backgroundColor = when (colors) { is Colors.Solid -> colors.backgroundColor is Colors.Gradient -> Color.Transparent }, contentColor = colors.textColor, - disabledContainerColor = when (colors) { + disabledBackgroundColor = when (colors) { is Colors.Solid -> colors.backgroundColor is Colors.Gradient -> Color.Transparent }, @@ -71,14 +69,13 @@ fun ButtonLayout( border = BorderStroke(shape.borderStroke, colors.borderColor), contentPadding = shape.paddings, enabled = enabled, - elevation = ButtonDefaults.buttonElevation( - defaultElevation = Elevation.none, - pressedElevation = Elevation.none, - disabledElevation = Elevation.none + elevation = ButtonDefaults.elevation( + defaultElevation = Elevation.zero, + pressedElevation = Elevation.zero, + disabledElevation = Elevation.zero ), interactionSource = interactionSource, modifier = modifier - .defaultMinSize(ButtonSize.minWidth, ButtonSize.minHeight) .shadow( elevation = appearance.shadowElevation, shape = RoundedCornerShape(shape.cornerRadius), diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt deleted file mode 100644 index 4229c35aa..000000000 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/ButtonExample.kt +++ /dev/null @@ -1,93 +0,0 @@ -package com.atls.hyperion.ui.components.button.stories - -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.runtime.Composable -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.dp -import com.atls.hyperion.ui.components.button.Button -import com.atls.hyperion.ui.components.button.style.appearance.ButtonAppearance -import com.atls.hyperion.ui.components.button.style.appearance.ButtonAppearanceColors -import com.atls.hyperion.ui.components.button.style.shape.ButtonShape -import com.atls.hyperion.storybook.shared.model.ComponentExample -import com.atls.hyperion.storybook.shared.ui.ComponentVariants -import com.atls.hyperion.ui.theme.tokens.colors.Colors - -class ButtonExample : ComponentExample { - override val name: String = "Button" - - @Composable - override fun Content() { - ComponentVariants( - name = "Button", - appearances = listOf( - "Primary Blue" to { primaryAppearance() }, - "Light Blue" to { lightBlueAppearance() } - ), - shapes = listOf( - "Large" to { largeShape() }, - "Medium" to { mediumShape() } - ) - ) { appearance: ButtonAppearance, shape: ButtonShape -> - Button( - text = "Button", - appearance = appearance, - shape = shape, - onClick = {} - ) - } - } -} - -@Composable -private fun primaryAppearance() = ButtonAppearance( - default = ButtonAppearanceColors( - backgroundColor = Colors.Button.Blue.Default.background, - textColor = Colors.Button.Blue.Default.font, - borderColor = Colors.Button.Blue.Default.border - ), - pressed = ButtonAppearanceColors( - backgroundColor = Colors.Button.Blue.Pressed.background, - textColor = Colors.Button.Blue.Pressed.font, - borderColor = Colors.Button.Blue.Pressed.border - ), - disabled = ButtonAppearanceColors( - backgroundColor = Colors.Button.Blue.Disabled.background, - textColor = Colors.Button.Blue.Disabled.font, - borderColor = Colors.Button.Blue.Disabled.border - ) -) - -@Composable -private fun lightBlueAppearance() = ButtonAppearance( - default = ButtonAppearanceColors( - backgroundColor = Colors.Button.LightBlue.Default.background, - textColor = Colors.Button.LightBlue.Default.font, - borderColor = Colors.Button.LightBlue.Default.border - ), - pressed = ButtonAppearanceColors( - backgroundColor = Colors.Button.LightBlue.Pressed.background, - textColor = Colors.Button.LightBlue.Pressed.font, - borderColor = Colors.Button.LightBlue.Pressed.border - ), - disabled = ButtonAppearanceColors( - backgroundColor = Colors.Button.LightBlue.Disabled.background, - textColor = Colors.Button.LightBlue.Disabled.font, - borderColor = Colors.Button.LightBlue.Disabled.border - ) -) - -@Composable -private fun largeShape() = ButtonShape( - cornerRadius = 8.dp, - paddings = PaddingValues(16.dp, 12.dp), - typography = TextStyle(), - borderStroke = 1.dp -) - -@Composable -private fun mediumShape() = ButtonShape( - cornerRadius = 4.dp, - paddings = PaddingValues(12.dp, 8.dp), - typography = TextStyle(), - borderStroke = 1.dp -) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt index c4ac2edd6..3ad7afe39 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Variants.kt @@ -1,112 +1,42 @@ package com.atls.hyperion.ui.components.button.styles.appearance -import androidx.compose.runtime.Composable -import com.atls.hyperion.ui.components.button.styles.appearance.colors.Colors -import com.atls.hyperion.ui.theme.Theme -import com.atls.hyperion.ui.theme.properties.shadow.Elevation +import com.atls.hyperion.ui.theme.tokens.colors.Colors +import com.atls.hyperion.ui.components.button.styles.appearance.Colors as ButtonColors -@Composable -fun ButtonAppearance.Companion.primary(): ButtonAppearance = +fun ButtonAppearance.Companion.blue(): ButtonAppearance = ButtonAppearance( - default = Colors.Solid( - backgroundColor = Theme.button.primary, - textColor = Theme.button.textPrimary - ), - pressed = Colors.Solid( - backgroundColor = Theme.button.primaryFocus, - textColor = Theme.button.textPrimaryFocus - ), - disabled = Colors.Solid( - backgroundColor = Theme.button.primaryDisabled, - textColor = Theme.button.textPrimaryDisabled - ) - ) - -@Composable -fun ButtonAppearance.Companion.secondary(): ButtonAppearance = - ButtonAppearance( - default = Colors.Solid( - backgroundColor = Theme.button.secondary, - textColor = Theme.text.secondary - ), - pressed = Colors.Solid( - backgroundColor = Theme.button.secondary, - textColor = Theme.button.textSecondaryFocus - ), - disabled = Colors.Solid( - backgroundColor = Theme.button.secondaryDisabled, - textColor = Theme.button.textSecondaryDisabled - ) - ) - - -@Composable -fun ButtonAppearance.Companion.ghost(): ButtonAppearance = - ButtonAppearance( - default = Colors.Solid( - backgroundColor = Theme.main.transparent, - textColor = Theme.text.secondary - ), - pressed = Colors.Solid( - backgroundColor = Theme.button.secondary, - textColor = Theme.button.textSecondaryFocus - ), - disabled = Colors.Solid( - backgroundColor = Theme.button.secondaryDisabled, - textColor = Theme.button.textSecondaryDisabled + default = ButtonColors.Solid( + backgroundColor = Colors.Button.Blue.Default.background, + textColor = Colors.Button.Blue.Default.font, + borderColor = Colors.Button.Blue.Default.border + ), + pressed = ButtonColors.Solid( + backgroundColor = Colors.Button.Blue.Pressed.background, + textColor = Colors.Button.Blue.Pressed.font, + borderColor = Colors.Button.Blue.Pressed.border + ), + disabled = ButtonColors.Solid( + backgroundColor = Colors.Button.Blue.Disabled.background, + textColor = Colors.Button.Blue.Disabled.font, + borderColor = Colors.Button.Blue.Disabled.border ) ) -@Composable -fun ButtonAppearance.Companion.gradient(): ButtonAppearance = +fun ButtonAppearance.Companion.lightBlue(): ButtonAppearance = ButtonAppearance( - default = Colors.Gradient( - backgroundBrush = Theme.button.backgroundGradient, - textColor = Theme.button.textPrimary, - ), - pressed = Colors.Gradient( - backgroundBrush = Theme.button.backgroundGradient, - textColor = Theme.button.textPrimaryFocus - ), - disabled = Colors.Gradient( - backgroundBrush = Theme.button.backgroundGradientDisabled, - textColor = Theme.button.textPrimary - ), - shadowElevation = Elevation.tiny - ) - -@Composable -fun ButtonAppearance.Companion.light(): ButtonAppearance = - ButtonAppearance( - default = Colors.Solid( - backgroundColor = Theme.contrastInverted.low, - textColor = Theme.button.textPrimary - ), - pressed = Colors.Solid( - backgroundColor = Theme.button.secondary, - textColor = Theme.button.textPrimaryFocus, - borderColor = Theme.contrastInverted.lower - ), - disabled = Colors.Solid( - backgroundColor = Theme.button.secondaryDisabled, - textColor = Theme.button.textPrimaryDisabled + default = ButtonColors.Solid( + backgroundColor = Colors.Button.LightBlue.Default.background, + textColor = Colors.Button.LightBlue.Default.font, + borderColor = Colors.Button.LightBlue.Default.border + ), + pressed = ButtonColors.Solid( + backgroundColor = Colors.Button.LightBlue.Pressed.background, + textColor = Colors.Button.LightBlue.Pressed.font, + borderColor = Colors.Button.LightBlue.Pressed.border + ), + disabled = ButtonColors.Solid( + backgroundColor = Colors.Button.LightBlue.Disabled.background, + textColor = Colors.Button.LightBlue.Disabled.font, + borderColor = Colors.Button.LightBlue.Disabled.border ) ) - -@Composable -fun ButtonAppearance.Companion.activity(): ButtonAppearance = - ButtonAppearance( - default = Colors.Solid( - backgroundColor = Theme.button.activity, - textColor = Theme.icon.link - ), - pressed = Colors.Solid( - backgroundColor = Theme.main.primary, - textColor = Theme.icon.invertedMain - ), - disabled = Colors.Solid( - backgroundColor = Theme.button.activity, - textColor = Theme.icon.link - ) - ) - diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt index a943d29c5..52448ba89 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt @@ -2,49 +2,72 @@ package com.atls.hyperion.ui.components.button.styles.shape import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable -import com.atls.hyperion.ui.theme.Theme -import com.atls.hyperion.ui.theme.properties.BorderStroke -import com.atls.hyperion.ui.theme.properties.CornerRadius -import com.atls.hyperion.ui.theme.properties.Padding +import androidx.compose.ui.text.TextStyle +import com.atls.hyperion.ui.theme.typography.FontSize +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.tokens.layout.Border +import com.atls.hyperion.ui.theme.typography.LineHeights + +@Composable +fun ButtonShape.Companion.huge(): ButtonShape = + ButtonShape( + cornerRadius = CornerRadius.xl4, + paddings = PaddingValues(horizontal = Space.g24, vertical = Space.g16), + typography = TextStyle(fontSize = FontSize.xl3, lineHeight = LineHeights.xl4), + borderStroke = Border.none.width + ) @Composable fun ButtonShape.Companion.large(): ButtonShape = ButtonShape( - cornerRadius = CornerRadius.regular, - paddings = PaddingValues( - horizontal = Padding.semiLarge, - vertical = Padding.small - ), - typography = Theme.typography.body.regular.large, - borderStroke = BorderStroke.tiny + cornerRadius = CornerRadius.xl4, + paddings = PaddingValues(horizontal = Space.g24, vertical = Space.g14), + typography = TextStyle(fontSize = FontSize.xl2, lineHeight = LineHeights.xl3), + borderStroke = Border.none.width + ) + +@Composable +fun ButtonShape.Companion.semiMedium(): ButtonShape = + ButtonShape( + cornerRadius = CornerRadius.xl4, + paddings = PaddingValues(horizontal = Space.g20, vertical = Space.g12), + typography = TextStyle(fontSize = FontSize.lg, lineHeight = LineHeights.xl), + borderStroke = Border.none.width + ) + +@Composable +fun ButtonShape.Companion.medium(): ButtonShape = + ButtonShape( + cornerRadius = CornerRadius.xl4, + paddings = PaddingValues(horizontal = Space.g16, vertical = Space.g10), + typography = TextStyle(fontSize = FontSize.md, lineHeight = LineHeights.md), + borderStroke = Border.none.width ) @Composable -fun ButtonShape.Companion.default(): ButtonShape = +fun ButtonShape.Companion.normal(): ButtonShape = ButtonShape( - cornerRadius = CornerRadius.small, - paddings = PaddingValues( - horizontal = Padding.medium, - vertical = Padding.xsmall - ), - typography = Theme.typography.caption.regular.large, - borderStroke = BorderStroke.tiny + cornerRadius = CornerRadius.xl4, + paddings = PaddingValues(horizontal = Space.g24, vertical = Space.g8), + typography = TextStyle(fontSize = FontSize.xs, lineHeight = LineHeights.sm), + borderStroke = Border.none.width ) @Composable -fun ButtonShape.Companion.rounded(): ButtonShape = +fun ButtonShape.Companion.small(): ButtonShape = ButtonShape( - cornerRadius = CornerRadius.full, - paddings = PaddingValues(Padding.xsmall), - typography = Theme.typography.caption.regular.large, - borderStroke = BorderStroke.none + cornerRadius = CornerRadius.xl4, + paddings = PaddingValues(horizontal = Space.g16, vertical = Space.g6), + typography = TextStyle(fontSize = FontSize.xs, lineHeight = LineHeights.xs), + borderStroke = Border.none.width ) @Composable -fun ButtonShape.Companion.activity(): ButtonShape = +fun ButtonShape.Companion.smallSizeMediumRadii(): ButtonShape = ButtonShape( - cornerRadius = CornerRadius.medium, - paddings = PaddingValues(Padding.medium), - typography = Theme.typography.body.regular.medium, - borderStroke = BorderStroke.none + cornerRadius = CornerRadius.xl2_5, + paddings = PaddingValues(horizontal = Space.g16, vertical = Space.g6), + typography = TextStyle(fontSize = FontSize.xs, lineHeight = LineHeights.xs), + borderStroke = Border.none.width ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt index 3209aeaad..4e723cf48 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt @@ -13,6 +13,7 @@ object Space { val g14 = 14.dp val g16 = 16.dp val g17 = 17.dp + val g20 = 20.dp val g22 = 22.dp val g24 = 24.dp } From 4ee53d993a485801bf990ae690b774c16218eabc Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 03:52:46 +0300 Subject: [PATCH 20/75] feat(ui): card component with styles --- .../hyperion/ui/components/card/Component.kt | 42 +++++++++++++++++++ .../ui/components/card/stories/Component.kt | 36 ++++++++++++++++ .../card/style/appearance/Appearance.kt | 13 ++++++ .../card/style/appearance/Variants.kt | 11 +++++ .../ui/components/card/style/shape/Shape.kt | 12 ++++++ .../components/card/style/shape/Variants.kt | 15 +++++++ 6 files changed, 129 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/Component.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/stories/Component.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/Component.kt new file mode 100644 index 000000000..593adc282 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/Component.kt @@ -0,0 +1,42 @@ +package com.atls.hyperion.ui.components.card + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.card.style.appearance.CardAppearance +import com.atls.hyperion.ui.components.card.style.shape.CardShape + +@Composable +fun Card( + modifier: Modifier = Modifier, + shape: CardShape, + appearance: CardAppearance, + contentAlignment: Alignment = Alignment.TopCenter, + content: @Composable BoxScope.() -> Unit +) { + Surface( + modifier = modifier, + shape = RoundedCornerShape(shape.cornerRadius), + color = appearance.backgroundColor, + elevation = appearance.elevation + ) { + Box( + modifier = Modifier + .border( + width = shape.borderWidth, + color = appearance.borderColor, + shape = RoundedCornerShape(shape.cornerRadius) + ) + .padding(shape.padding), + contentAlignment = contentAlignment + ) { + content() + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/stories/Component.kt new file mode 100644 index 000000000..32df3a532 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/stories/Component.kt @@ -0,0 +1,36 @@ +package com.atls.hyperion.ui.components.card.stories + +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.components.card.Card +import com.atls.hyperion.ui.components.card.style.appearance.CardAppearance +import com.atls.hyperion.ui.components.card.style.appearance.white +import com.atls.hyperion.ui.components.card.style.shape.CardShape +import com.atls.hyperion.ui.components.card.style.shape.medium + +class CardStory : ComponentExample { + + override val name: String = "Card" + + @Composable + override fun Content() { + ComponentVariants( + name = "Card", + appearances = listOf( + "White" to { CardAppearance.white() } + ), + shapes = listOf( + "Medium" to { CardShape.medium() } + ) + ) { appearance: CardAppearance, shape: CardShape -> + Card( + appearance = appearance, + shape = shape + ) { + Text("Card Content") + } + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt new file mode 100644 index 000000000..f07f4a2f2 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt @@ -0,0 +1,13 @@ +package com.atls.hyperion.ui.components.card.style.appearance + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.theme.tokens.Elevation + +data class CardAppearance( + val backgroundColor: Color, + val borderColor: Color = Color.Transparent, + val elevation: Dp = Elevation.zero +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Variants.kt new file mode 100644 index 000000000..817ef379f --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Variants.kt @@ -0,0 +1,11 @@ +package com.atls.hyperion.ui.components.card.style.appearance + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.colors.Colors + +@Composable +fun CardAppearance.Companion.white(): CardAppearance = + CardAppearance( + backgroundColor = Colors.Palette.white, + borderColor = Colors.Palette.gray + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Shape.kt new file mode 100644 index 000000000..a1dc3011d --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Shape.kt @@ -0,0 +1,12 @@ +package com.atls.hyperion.ui.components.card.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.unit.Dp + +data class CardShape( + val cornerRadius: Dp, + val padding: PaddingValues, + val borderWidth: Dp +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt new file mode 100644 index 000000000..9b31aba8c --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt @@ -0,0 +1,15 @@ +package com.atls.hyperion.ui.components.card.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.layout.Border +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Space + +@Composable +fun CardShape.Companion.medium(): CardShape = + CardShape( + cornerRadius = CornerRadius.xl, + padding = PaddingValues(Space.g16), + borderWidth = Border.none.width + ) From 6f5b8d371b85755c145843556b3c178c766000c7 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:23:22 +0300 Subject: [PATCH 21/75] feat(ui): avatar styles --- .../avatar/styles/appearance/Appearance.kt | 10 ++++ .../avatar/styles/appearance/Variants.kt | 11 +++++ .../components/avatar/styles/shape/Shape.kt | 12 +++++ .../avatar/styles/shape/Variants.kt | 47 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Appearance.kt new file mode 100644 index 000000000..243f0b678 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Appearance.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.components.avatar.styles.appearance + +import androidx.compose.ui.graphics.Color + +data class AvatarAppearance( + val backgroundColor: Color, + val borderColor: Color +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt new file mode 100644 index 000000000..b960cbac7 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt @@ -0,0 +1,11 @@ +package com.atls.hyperion.ui.components.avatar.styles.appearance + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +@Composable +fun AvatarAppearance.Companion.default(): AvatarAppearance = + AvatarAppearance( + backgroundColor = Color.Transparent, + borderColor = Color.Transparent + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt new file mode 100644 index 000000000..ba7c883d8 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt @@ -0,0 +1,12 @@ +package com.atls.hyperion.ui.components.avatar.styles.shape + +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.theme.tokens.layout.Border + +data class AvatarShape( + val size: Dp, + val cornerRadius: Dp, + val borderStroke: Dp = Border.none.width +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt new file mode 100644 index 000000000..3a90330cf --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt @@ -0,0 +1,47 @@ +package com.atls.hyperion.ui.components.avatar.styles.shape + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.components.ImageSize +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius + +@Composable +fun AvatarShape.Companion.smallCircle(): AvatarShape = + AvatarShape( + size = ImageSize.medium, + cornerRadius = CornerRadius.full + ) + +@Composable +fun AvatarShape.Companion.normalCircle(): AvatarShape = + AvatarShape( + size = ImageSize.large, + cornerRadius = CornerRadius.full + ) + +@Composable +fun AvatarShape.Companion.largeCircle(): AvatarShape = + AvatarShape( + size = ImageSize.huge, + cornerRadius = CornerRadius.full + ) + +@Composable +fun AvatarShape.Companion.smallSquare(): AvatarShape = + AvatarShape( + size = ImageSize.medium, + cornerRadius = CornerRadius.xs3 + ) + +@Composable +fun AvatarShape.Companion.normalSquare(): AvatarShape = + AvatarShape( + size = ImageSize.large, + cornerRadius = CornerRadius.xs3 + ) + +@Composable +fun AvatarShape.Companion.largeSquare(): AvatarShape = + AvatarShape( + size = ImageSize.huge, + cornerRadius = CornerRadius.xs3 + ) From c85acc4765403aa13cd3ea9e060daf4d5f95a86c Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:23:36 +0300 Subject: [PATCH 22/75] feat(ui): avatar component --- .../ui/components/avatar/Component.kt | 68 +++++++++++++++++++ .../hyperion/ui/components/avatar/Layout.kt | 36 ++++++++++ .../ui/components/avatar/stories/Component.kt | 43 ++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Layout.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/stories/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt new file mode 100644 index 000000000..e6648273e --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt @@ -0,0 +1,68 @@ +package com.atls.hyperion.ui.components.avatar + +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale +import coil3.compose.AsyncImage +import com.atls.hyperion.ui.components.avatar.styles.appearance.AvatarAppearance +import com.atls.hyperion.ui.components.avatar.styles.shape.AvatarShape +import com.atls.hyperion.ui.primitives.Image + +@Composable +fun Avatar( + modifier: Modifier = Modifier, + appearance: AvatarAppearance, + shape: AvatarShape, + content: @Composable BoxScope.() -> Unit = {} +) { + AvatarLayout( + modifier = modifier, + appearance = appearance, + shape = shape, + content = content + ) +} + +@Composable +fun Avatar( + modifier: Modifier = Modifier, + image: Painter, + appearance: AvatarAppearance, + shape: AvatarShape, + contentScale: ContentScale = ContentScale.Fit +) { + AvatarLayout( + modifier = modifier, + appearance = appearance, + shape = shape + ) { + Image( + image = image, + contentScale = contentScale + ) + } +} + +@Composable +fun Avatar( + modifier: Modifier = Modifier, + imageUrl: String, + appearance: AvatarAppearance, + shape: AvatarShape +) { + AvatarLayout( + modifier = modifier, + appearance = appearance, + shape = shape + ) { + AsyncImage( + modifier = Modifier + .matchParentSize(), + model = imageUrl, + contentScale = ContentScale.Crop, + contentDescription = null + ) + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Layout.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Layout.kt new file mode 100644 index 000000000..82985fcea --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Layout.kt @@ -0,0 +1,36 @@ +package com.atls.hyperion.ui.components.avatar + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import com.atls.hyperion.ui.components.avatar.styles.appearance.AvatarAppearance +import com.atls.hyperion.ui.components.avatar.styles.shape.AvatarShape + +@Composable +fun AvatarLayout( + modifier: Modifier = Modifier, + appearance: AvatarAppearance, + shape: AvatarShape, + content: @Composable BoxScope.() -> Unit +) { + Box( + modifier = modifier + .size(shape.size) + .border( + shape.borderStroke, + appearance.borderColor + ) + .clip(RoundedCornerShape(shape.cornerRadius)) + .background(appearance.backgroundColor), + contentAlignment = Alignment.Center + ) { + content() + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/stories/Component.kt new file mode 100644 index 000000000..d04c18301 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/stories/Component.kt @@ -0,0 +1,43 @@ +package com.atls.hyperion.ui.components.avatar.stories + +import androidx.compose.runtime.Composable +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.components.avatar.Avatar +import com.atls.hyperion.ui.components.avatar.styles.appearance.AvatarAppearance +import com.atls.hyperion.ui.components.avatar.styles.appearance.default +import com.atls.hyperion.ui.components.avatar.styles.shape.AvatarShape +import com.atls.hyperion.ui.components.avatar.styles.shape.largeCircle +import com.atls.hyperion.ui.components.avatar.styles.shape.largeSquare +import com.atls.hyperion.ui.components.avatar.styles.shape.normalCircle +import com.atls.hyperion.ui.components.avatar.styles.shape.normalSquare +import com.atls.hyperion.ui.components.avatar.styles.shape.smallCircle +import com.atls.hyperion.ui.components.avatar.styles.shape.smallSquare + +class AvatarStory : ComponentExample { + override val name: String = "Avatar" + + @Composable + override fun Content() { + ComponentVariants( + name = "Avatar", + appearances = listOf( + "Default" to { AvatarAppearance.default() } + ), + shapes = listOf( + "Small Circle" to { AvatarShape.smallCircle() }, + "Normal Circle" to { AvatarShape.normalCircle() }, + "Large Circle" to { AvatarShape.largeCircle() }, + "Small Square" to { AvatarShape.smallSquare() }, + "Normal Square" to { AvatarShape.normalSquare() }, + "Large Square" to { AvatarShape.largeSquare() } + ) + ) { appearance: AvatarAppearance, shape: AvatarShape -> + Avatar( + appearance = appearance, + shape = shape, + imageUrl = "https://media.istockphoto.com/id/1224772234/ru/фото/портрет-полосатой-кошки-с-зелеными-глазами-на-сером-фоне-кошка-смотрит-прямо-в-камеру.jpg?s=612x612&w=0&k=20&c=W5q6PFsJhSNgDuyHwi-xSSUaftlrfToSFix31JJ2eVU=" + ) + } + } +} From a5ee798a70de01c709c2c4d06e8609818e28eb59 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:49:31 +0300 Subject: [PATCH 23/75] feat(ui): checkbox styles --- .../checkbox/styles/appearance/Appearance.kt | 19 ++++++ .../checkbox/styles/appearance/Colors.kt | 9 +++ .../checkbox/styles/appearance/Variants.kt | 60 +++++++++++++++++++ .../components/checkbox/styles/shape/Shape.kt | 14 +++++ .../checkbox/styles/shape/Variants.kt | 26 ++++++++ 5 files changed, 128 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Appearance.kt new file mode 100644 index 000000000..3155675d9 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Appearance.kt @@ -0,0 +1,19 @@ +package com.atls.hyperion.ui.components.checkbox.styles.appearance + +import com.atls.hyperion.ui.components.checkbox.state.State + +data class CheckboxAppearance( + val default: Colors, + val checked: Colors, + val disabled: Colors +) { + fun fromState(state: State): Colors { + return when (state) { + State.Default -> default + State.Checked -> checked + State.Disabled -> disabled + } + } + + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt new file mode 100644 index 000000000..04fc113e1 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.components.checkbox.styles.appearance + +import androidx.compose.ui.graphics.Color + +data class Colors( + val backgroundColor: Color, + val borderColor: Color = Color.Transparent, + val checkColor: Color +) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt new file mode 100644 index 000000000..fa39a42e5 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt @@ -0,0 +1,60 @@ +package com.atls.hyperion.ui.components.checkbox.styles.appearance + +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors + +fun CheckboxAppearance.Companion.blue(): CheckboxAppearance = + CheckboxAppearance( + default = Colors( + backgroundColor = ThemeColors.Checkbox.Blue.Default.background, + borderColor = ThemeColors.Checkbox.Blue.Default.border, + checkColor = ThemeColors.Checkbox.Blue.Default.font + ), + checked = Colors( + backgroundColor = ThemeColors.Checkbox.Blue.Default.background, + borderColor = ThemeColors.Checkbox.Blue.Default.border, + checkColor = ThemeColors.Checkbox.Blue.Default.font + ), + disabled = Colors( + backgroundColor = ThemeColors.Checkbox.Blue.Default.background, + borderColor = ThemeColors.Checkbox.Blue.Default.border, + checkColor = ThemeColors.Checkbox.Blue.Default.font + ) + ) + +fun CheckboxAppearance.Companion.green(): CheckboxAppearance = + CheckboxAppearance( + default = Colors( + backgroundColor = ThemeColors.Checkbox.Green.Default.background, + borderColor = ThemeColors.Checkbox.Green.Default.border, + checkColor = ThemeColors.Checkbox.Green.Default.font + ), + checked = Colors( + backgroundColor = ThemeColors.Checkbox.Green.Default.background, + borderColor = ThemeColors.Checkbox.Green.Default.border, + checkColor = ThemeColors.Checkbox.Green.Default.font + ), + disabled = Colors( + backgroundColor = ThemeColors.Checkbox.Green.Default.background, + borderColor = ThemeColors.Checkbox.Green.Default.border, + checkColor = ThemeColors.Checkbox.Green.Default.font + ) + ) + +fun CheckboxAppearance.Companion.red(): CheckboxAppearance = + CheckboxAppearance( + default = Colors( + backgroundColor = ThemeColors.Checkbox.Red.Default.background, + borderColor = ThemeColors.Checkbox.Red.Default.border, + checkColor = ThemeColors.Checkbox.Red.Default.font + ), + checked = Colors( + backgroundColor = ThemeColors.Checkbox.Red.Default.background, + borderColor = ThemeColors.Checkbox.Red.Default.border, + checkColor = ThemeColors.Checkbox.Red.Default.font + ), + disabled = Colors( + backgroundColor = ThemeColors.Checkbox.Red.Default.background, + borderColor = ThemeColors.Checkbox.Red.Default.border, + checkColor = ThemeColors.Checkbox.Red.Default.font + ) + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Shape.kt new file mode 100644 index 000000000..382b03759 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Shape.kt @@ -0,0 +1,14 @@ +package com.atls.hyperion.ui.components.checkbox.styles.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.theme.tokens.layout.Space + +data class CheckboxShape( + val size: Dp, + val cornerRadius: Dp, + val borderStroke: Dp, + val padding: PaddingValues = PaddingValues(Space.g2) +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt new file mode 100644 index 000000000..9c5c921f0 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt @@ -0,0 +1,26 @@ +package com.atls.hyperion.ui.components.checkbox.styles.shape + +import com.atls.hyperion.ui.theme.tokens.components.CheckboxSize +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius + +fun CheckboxShape.Companion.small(): CheckboxShape = + CheckboxShape( + size = CheckboxSize.small, + cornerRadius = CornerRadius.xs3, + borderStroke = BorderStroke.tiny + ) + +fun CheckboxShape.Companion.medium(): CheckboxShape = + CheckboxShape( + size = CheckboxSize.medium, + cornerRadius = CornerRadius.xs3, + borderStroke = BorderStroke.tiny + ) + +fun CheckboxShape.Companion.large(): CheckboxShape = + CheckboxShape( + size = CheckboxSize.large, + cornerRadius = CornerRadius.xs3, + borderStroke = BorderStroke.tiny + ) From 2b2e863a72e15c26ab62b5c0d7712453f2570b3c Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:49:38 +0300 Subject: [PATCH 24/75] feat(ui): checkbox state --- .../atls/hyperion/ui/components/checkbox/locals/State.kt | 6 ++++++ .../atls/hyperion/ui/components/checkbox/state/State.kt | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/locals/State.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/state/State.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/locals/State.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/locals/State.kt new file mode 100644 index 000000000..f0ac4fc75 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/locals/State.kt @@ -0,0 +1,6 @@ +package com.atls.hyperion.ui.components.checkbox.locals + +import androidx.compose.runtime.staticCompositionLocalOf +import com.atls.hyperion.ui.components.checkbox.state.State + +val LocalState = staticCompositionLocalOf { State.Default } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/state/State.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/state/State.kt new file mode 100644 index 000000000..c21be7925 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/state/State.kt @@ -0,0 +1,7 @@ +package com.atls.hyperion.ui.components.checkbox.state + +enum class State { + Default, + Checked, + Disabled +} From 97d3091e0fd941a0622874a26059875120408ff6 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:49:55 +0300 Subject: [PATCH 25/75] feat(ui): checkbox component with story --- .../ui/components/checkbox/Component.kt | 71 ++++++++++++++++++ .../components/checkbox/stories/Component.kt | 75 +++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/stories/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt new file mode 100644 index 000000000..f09cb7708 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt @@ -0,0 +1,71 @@ +package com.atls.hyperion.ui.components.checkbox + +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.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import com.atls.hyperion.ui.components.checkbox.locals.LocalState +import com.atls.hyperion.ui.components.checkbox.state.State +import com.atls.hyperion.ui.components.checkbox.styles.appearance.CheckboxAppearance +import com.atls.hyperion.ui.components.checkbox.styles.shape.CheckboxShape +import com.atls.hyperion.ui.primitives.Icon +import com.atls.hyperion.ui.theme.tokens.layout.Weight + +@Composable +fun Checkbox( + modifier: Modifier = Modifier, + state: State = State.Default, + appearance: CheckboxAppearance, + shape: CheckboxShape, + icon: Painter? = null, + onCheckedChange: ((Boolean) -> Unit)? = null +) { + CompositionLocalProvider(LocalState provides state) { + val state = LocalState.current + val colors = appearance.fromState(state) + + Box( + modifier = modifier + .size(shape.size) + .background( + color = colors.backgroundColor, + shape = RoundedCornerShape(shape.cornerRadius) + ) + .border( + width = shape.borderStroke, + color = colors.borderColor, + shape = RoundedCornerShape(shape.cornerRadius) + ) + .clickable { + onCheckedChange?.let { it(state != State.Checked) } + }, + contentAlignment = Alignment.Center + ) { + if (state == State.Checked && icon != null) { + Icon( + icon = icon, + color = colors.checkColor, + size = shape.size * Weight.large + ) + } else if (state == State.Checked) { + Box( + modifier = Modifier + .padding(shape.padding) + .matchParentSize() + .background( + color = colors.checkColor, + shape = RoundedCornerShape(shape.cornerRadius) + ) + ) + } + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/stories/Component.kt new file mode 100644 index 000000000..53ceb1ba2 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/stories/Component.kt @@ -0,0 +1,75 @@ +package com.atls.hyperion.ui.components.checkbox.stories + +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.material.Switch +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.components.checkbox.Checkbox +import com.atls.hyperion.ui.components.checkbox.state.State +import com.atls.hyperion.ui.components.checkbox.styles.appearance.CheckboxAppearance +import com.atls.hyperion.ui.components.checkbox.styles.appearance.blue +import com.atls.hyperion.ui.components.checkbox.styles.appearance.green +import com.atls.hyperion.ui.components.checkbox.styles.appearance.red +import com.atls.hyperion.ui.components.checkbox.styles.shape.CheckboxShape +import com.atls.hyperion.ui.components.checkbox.styles.shape.large +import com.atls.hyperion.ui.components.checkbox.styles.shape.medium +import com.atls.hyperion.ui.components.checkbox.styles.shape.small +import com.atls.hyperion.ui.primitives.HorizontalSpacer +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.tokens.layout.Weight + +class CheckboxStory : ComponentExample { + override val name: String = "Checkbox" + + @Composable + override fun Content() { + var checked by remember { mutableStateOf(false) } + + var enabled by remember { mutableStateOf(true) } + + Column { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = Space.g12) + ) { + Text(modifier = Modifier.weight(Weight.full), text = "Enabled") + HorizontalSpacer(Space.g12) + Switch(checked = enabled, onCheckedChange = { enabled = it }) + } + VerticalSpacer(Space.g12) + + ComponentVariants( + name = "Checkbox", + appearances = listOf( + "Blue" to { CheckboxAppearance.blue() }, + "Green" to { CheckboxAppearance.green() }, + "Red" to { CheckboxAppearance.red() } + ), + shapes = listOf( + "Small" to { CheckboxShape.small() }, + "Medium" to { CheckboxShape.medium() }, + "Large" to { CheckboxShape.large() } + ) + ) { appearance: CheckboxAppearance, shape: CheckboxShape -> + Checkbox( + state = if (checked) State.Checked else if (!enabled) State.Disabled else State.Default, + appearance = appearance, + shape = shape, + onCheckedChange = { checked = it } + ) + } + } + } +} From 3673050f1568360a0add790ad36b51befedb529d Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:51:03 +0300 Subject: [PATCH 26/75] feat(ui): divider styles --- .../components/divider/style/appearance/Appearance.kt | 9 +++++++++ .../ui/components/divider/style/appearance/Variants.kt | 10 ++++++++++ .../ui/components/divider/style/shape/DividerShape.kt | 9 +++++++++ .../ui/components/divider/style/shape/Variants.kt | 10 ++++++++++ 4 files changed, 38 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/DividerShape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Appearance.kt new file mode 100644 index 000000000..6269191be --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Appearance.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.components.divider.style.appearance + +import androidx.compose.ui.graphics.Color + +data class DividerAppearance( + val color: Color +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Variants.kt new file mode 100644 index 000000000..0f451f5b1 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/appearance/Variants.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.components.divider.style.appearance + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.colors.Colors + +@Composable +fun DividerAppearance.Companion.default(): DividerAppearance = + DividerAppearance( + color = Colors.Palette.lightPurple + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/DividerShape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/DividerShape.kt new file mode 100644 index 000000000..08e246158 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/DividerShape.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.components.divider.style.shape + +import androidx.compose.ui.unit.Dp + +data class DividerShape( + val thickness: Dp +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/Variants.kt new file mode 100644 index 000000000..5ab7437d6 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/style/shape/Variants.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.components.divider.style.shape + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke + +@Composable +fun DividerShape.Companion.default(): DividerShape = + DividerShape( + thickness = BorderStroke.tiny + ) From 234b4e4e98f27a569656c509ae3e938a33556e61 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:51:11 +0300 Subject: [PATCH 27/75] feat(ui): divider components --- .../divider/horizontal/HorizontalDivider.kt | 22 +++++++ .../divider/stories/DividerStory.kt | 59 +++++++++++++++++++ .../divider/vertical/VerticalDivider.kt | 26 ++++++++ 3 files changed, 107 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/HorizontalDivider.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/stories/DividerStory.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/VerticalDivider.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/HorizontalDivider.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/HorizontalDivider.kt new file mode 100644 index 000000000..1a0574401 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/HorizontalDivider.kt @@ -0,0 +1,22 @@ +package com.atls.hyperion.ui.components.divider.horizontal + +import androidx.compose.material.Divider +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance +import com.atls.hyperion.ui.components.divider.style.appearance.default +import com.atls.hyperion.ui.components.divider.style.shape.DividerShape +import com.atls.hyperion.ui.components.divider.style.shape.default + +@Composable +fun HorizontalDivider( + modifier: Modifier = Modifier, + appearance: DividerAppearance = DividerAppearance.default(), + shape: DividerShape = DividerShape.default() +) { + Divider( + modifier = modifier, + color = appearance.color, + thickness = shape.thickness + ) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/stories/DividerStory.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/stories/DividerStory.kt new file mode 100644 index 000000000..fec542066 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/stories/DividerStory.kt @@ -0,0 +1,59 @@ +package com.atls.hyperion.ui.components.divider.stories + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.components.divider.horizontal.HorizontalDivider +import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance +import com.atls.hyperion.ui.components.divider.style.appearance.default +import com.atls.hyperion.ui.components.divider.style.shape.DividerShape +import com.atls.hyperion.ui.components.divider.style.shape.default +import com.atls.hyperion.ui.components.divider.vertical.VerticalDivider +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.layout.Space + +class DividerStory : ComponentExample { + override val name: String = "Divider" + + @Composable + override fun Content() { + Column(modifier = Modifier.padding(Space.g12)) { + ComponentVariants( + name = "Horizontal Divider", + appearances = listOf( + "Default" to { DividerAppearance.default() } + ), + shapes = listOf( + "Default" to { DividerShape.default() } + ) + ) { appearance: DividerAppearance, shape: DividerShape -> + HorizontalDivider( + appearance = appearance, + shape = shape + ) + } + + VerticalSpacer(Space.g24) + + ComponentVariants( + name = "Vertical Divider", + appearances = listOf( + "Default" to { DividerAppearance.default() } + ), + shapes = listOf( + "Default" to { DividerShape.default() } + ) + ) { appearance: DividerAppearance, shape: DividerShape -> + VerticalDivider( + modifier = Modifier.height(Space.g24), + appearance = appearance, + shape = shape + ) + } + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/VerticalDivider.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/VerticalDivider.kt new file mode 100644 index 000000000..21c7932e3 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/VerticalDivider.kt @@ -0,0 +1,26 @@ +package com.atls.hyperion.ui.components.divider.vertical + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance +import com.atls.hyperion.ui.components.divider.style.appearance.default +import com.atls.hyperion.ui.components.divider.style.shape.DividerShape +import com.atls.hyperion.ui.components.divider.style.shape.default + +@Composable +fun VerticalDivider( + modifier: Modifier = Modifier, + appearance: DividerAppearance = DividerAppearance.default(), + shape: DividerShape = DividerShape.default() +) { + Box( + modifier = modifier + .fillMaxHeight() + .width(shape.thickness) + .background(color = appearance.color) + ) +} From 142f51b160bf99e8ba4143a93a4dea9c0f05c7d4 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:52:14 +0300 Subject: [PATCH 28/75] refactor(ui): border token --- .../components/avatar/styles/shape/Shape.kt | 4 ++-- .../button/styles/shape/Variants.kt | 18 +++++++------- .../components/card/style/shape/Variants.kt | 4 ++-- .../ui/theme/tokens/layout/Borders.kt | 24 +++---------------- 4 files changed, 16 insertions(+), 34 deletions(-) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt index ba7c883d8..5a067c91e 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Shape.kt @@ -1,12 +1,12 @@ package com.atls.hyperion.ui.components.avatar.styles.shape import androidx.compose.ui.unit.Dp -import com.atls.hyperion.ui.theme.tokens.layout.Border +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke data class AvatarShape( val size: Dp, val cornerRadius: Dp, - val borderStroke: Dp = Border.none.width + val borderStroke: Dp = BorderStroke.none ) { companion object } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt index 52448ba89..ffb849f56 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/shape/Variants.kt @@ -3,10 +3,10 @@ package com.atls.hyperion.ui.components.button.styles.shape import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable import androidx.compose.ui.text.TextStyle -import com.atls.hyperion.ui.theme.typography.FontSize +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius import com.atls.hyperion.ui.theme.tokens.layout.Space -import com.atls.hyperion.ui.theme.tokens.layout.Border +import com.atls.hyperion.ui.theme.typography.FontSize import com.atls.hyperion.ui.theme.typography.LineHeights @Composable @@ -15,7 +15,7 @@ fun ButtonShape.Companion.huge(): ButtonShape = cornerRadius = CornerRadius.xl4, paddings = PaddingValues(horizontal = Space.g24, vertical = Space.g16), typography = TextStyle(fontSize = FontSize.xl3, lineHeight = LineHeights.xl4), - borderStroke = Border.none.width + borderStroke = BorderStroke.none ) @Composable @@ -24,7 +24,7 @@ fun ButtonShape.Companion.large(): ButtonShape = cornerRadius = CornerRadius.xl4, paddings = PaddingValues(horizontal = Space.g24, vertical = Space.g14), typography = TextStyle(fontSize = FontSize.xl2, lineHeight = LineHeights.xl3), - borderStroke = Border.none.width + borderStroke = BorderStroke.none ) @Composable @@ -33,7 +33,7 @@ fun ButtonShape.Companion.semiMedium(): ButtonShape = cornerRadius = CornerRadius.xl4, paddings = PaddingValues(horizontal = Space.g20, vertical = Space.g12), typography = TextStyle(fontSize = FontSize.lg, lineHeight = LineHeights.xl), - borderStroke = Border.none.width + borderStroke = BorderStroke.none ) @Composable @@ -42,7 +42,7 @@ fun ButtonShape.Companion.medium(): ButtonShape = cornerRadius = CornerRadius.xl4, paddings = PaddingValues(horizontal = Space.g16, vertical = Space.g10), typography = TextStyle(fontSize = FontSize.md, lineHeight = LineHeights.md), - borderStroke = Border.none.width + borderStroke = BorderStroke.none ) @Composable @@ -51,7 +51,7 @@ fun ButtonShape.Companion.normal(): ButtonShape = cornerRadius = CornerRadius.xl4, paddings = PaddingValues(horizontal = Space.g24, vertical = Space.g8), typography = TextStyle(fontSize = FontSize.xs, lineHeight = LineHeights.sm), - borderStroke = Border.none.width + borderStroke = BorderStroke.none ) @Composable @@ -60,7 +60,7 @@ fun ButtonShape.Companion.small(): ButtonShape = cornerRadius = CornerRadius.xl4, paddings = PaddingValues(horizontal = Space.g16, vertical = Space.g6), typography = TextStyle(fontSize = FontSize.xs, lineHeight = LineHeights.xs), - borderStroke = Border.none.width + borderStroke = BorderStroke.none ) @Composable @@ -69,5 +69,5 @@ fun ButtonShape.Companion.smallSizeMediumRadii(): ButtonShape = cornerRadius = CornerRadius.xl2_5, paddings = PaddingValues(horizontal = Space.g16, vertical = Space.g6), typography = TextStyle(fontSize = FontSize.xs, lineHeight = LineHeights.xs), - borderStroke = Border.none.width + borderStroke = BorderStroke.none ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt index 9b31aba8c..7fa6617d5 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/shape/Variants.kt @@ -2,7 +2,7 @@ package com.atls.hyperion.ui.components.card.style.shape import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable -import com.atls.hyperion.ui.theme.tokens.layout.Border +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius import com.atls.hyperion.ui.theme.tokens.layout.Space @@ -11,5 +11,5 @@ fun CardShape.Companion.medium(): CardShape = CardShape( cornerRadius = CornerRadius.xl, padding = PaddingValues(Space.g16), - borderWidth = Border.none.width + borderWidth = BorderStroke.none ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt index 2fb4e1852..ef8a9668a 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Borders.kt @@ -1,26 +1,8 @@ package com.atls.hyperion.ui.theme.tokens.layout -import androidx.compose.foundation.BorderStroke -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -object Border { - val none: BorderStroke = BorderStroke(0.dp, Color.Transparent) - val thinLightBlue = BorderStroke(0.5.dp, Color(0xFFD2DDF9)) - val thinLightGray = BorderStroke(0.5.dp, Color(0xFFE4E4E4)) - val normalGray = BorderStroke(1.dp, Color(0xFF727272)) - val normalSilver = BorderStroke(1.dp, Color(0xFFE0E0E0)) - val normalCloudyWhite = BorderStroke(1.dp, Color(0xFFE4E4E4)) - val normalBlue = BorderStroke(1.dp, Color(0xFF416DDF)) - val normalLightGray = BorderStroke(1.dp, Color(0xFFB8B8B8)) - val normalLightBlue = BorderStroke(1.dp, Color(0xFFE8EDFB)) - val normalSoftBlue = BorderStroke(1.dp, Color(0xFF1270FC)) - val normalMediumGray = BorderStroke(1.dp, Color(0xFFD4D4D4)) - val normalConcrete = BorderStroke(1.dp, Color(0xFFF3F3F3)) - val mediumBlue = BorderStroke(3.dp, Color(0xFF416DDF)) - val mediumLightBlue = BorderStroke(3.dp, Color(0xFFE8EDFB)) - val bigLightBlue = BorderStroke(7.dp, Color(0xFFDBD6FF)) - val bigWhite = BorderStroke(6.dp, Color(0xFFFFFFFF)) - val dashedGray = BorderStroke(2.dp, Color(0xFFB8B8B8)) - val dashedBlue = BorderStroke(2.dp, Color(0xFF416DDF)) +object BorderStroke { + val none = 0.dp + val tiny = 1.dp } From 38f3193716dfc27b79dc84f64f26a83a8455de63 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:52:33 +0300 Subject: [PATCH 29/75] feat(ui): weight token --- .../atls/hyperion/ui/components/button/stories/Component.kt | 3 ++- .../com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt | 1 + .../com/atls/hyperion/ui/theme/tokens/layout/Weight.kt | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Weight.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt index 633bb3a69..af661f4a5 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/stories/Component.kt @@ -29,6 +29,7 @@ import com.atls.hyperion.ui.components.button.styles.shape.smallSizeMediumRadii import com.atls.hyperion.ui.primitives.HorizontalSpacer import com.atls.hyperion.ui.primitives.VerticalSpacer import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.tokens.layout.Weight class ButtonStory : ComponentExample { override val name: String = "Button" @@ -43,7 +44,7 @@ class ButtonStory : ComponentExample { .fillMaxWidth() .padding(horizontal = Space.g12) ) { - Text(modifier = Modifier.weight(1f), text = "Enabled") + Text(modifier = Modifier.weight(Weight.full), text = "Enabled") HorizontalSpacer(Space.g12) Switch(checked = enabled, onCheckedChange = { enabled = it }) } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt index 4e723cf48..119557275 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Spaces.kt @@ -5,6 +5,7 @@ import androidx.compose.ui.unit.dp object Space { val zero = 0.dp val g1 = 1.dp + val g2 = 2.dp val g4 = 4.dp val g6 = 6.dp val g8 = 8.dp diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Weight.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Weight.kt new file mode 100644 index 000000000..c5a93acc9 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Weight.kt @@ -0,0 +1,6 @@ +package com.atls.hyperion.ui.theme.tokens.layout + +object Weight { + val full = 1f + val large = 0.7f +} From 1f464876e59b7c5f5685e9a2805e7d4679e00db2 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:53:14 +0300 Subject: [PATCH 30/75] feat(ui): icon primitive --- .../com/atls/hyperion/ui/primitives/Icon.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Icon.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Icon.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Icon.kt new file mode 100644 index 000000000..9aafb876d --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Icon.kt @@ -0,0 +1,24 @@ +package com.atls.hyperion.ui.primitives + +import androidx.compose.foundation.layout.size +import androidx.compose.material.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.unit.Dp + +@Composable +fun Icon( + modifier: Modifier = Modifier, + icon: Painter, + color: Color = Color.Unspecified, + size: Dp = Dp.Unspecified +) { + Icon( + painter = icon, + contentDescription = null, + tint = color, + modifier = modifier.size(size = size) + ) +} From c7ac81babb13aaf7aa9d5bdcba898150d061b24f Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:53:27 +0300 Subject: [PATCH 31/75] feat(ui): image components --- .../com/atls/hyperion/ui/primitives/Image.kt | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Image.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Image.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Image.kt new file mode 100644 index 000000000..c67176d2f --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Image.kt @@ -0,0 +1,55 @@ +package com.atls.hyperion.ui.primitives + +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.painterResource + +@Composable +fun Image( + modifier: Modifier = Modifier, + image: DrawableResource, + contentScale: ContentScale = ContentScale.Fit, + contentDescription: String? = null +) { + Image( + painter = painterResource(image), + contentDescription = contentDescription, + contentScale = contentScale, + modifier = modifier + ) +} + +@Composable +fun Image( + modifier: Modifier = Modifier, + image: ImageVector, + contentScale: ContentScale = ContentScale.Fit, + contentDescription: String? = null +) { + Image( + imageVector = image, + contentDescription = contentDescription, + contentScale = contentScale, + modifier = modifier + ) +} + +@Composable +fun Image( + modifier: Modifier = Modifier, + image: Painter, + contentScale: ContentScale = ContentScale.Fit, + contentDescription: String? = null +) { + Image( + painter = image, + contentDescription = contentDescription, + contentScale = contentScale, + modifier = modifier + ) +} From 3bd2482aae312a3a9ebf3787d4fd1edefe335b84 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:53:49 +0300 Subject: [PATCH 32/75] feat(ui): link components --- .../com/atls/hyperion/ui/primitives/Link.kt | 45 +++++++++++++++ .../hyperion/ui/primitives/stories/Link.kt | 55 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Link.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Link.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Link.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Link.kt new file mode 100644 index 000000000..6464ae359 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Link.kt @@ -0,0 +1,45 @@ +package com.atls.hyperion.ui.primitives + +import androidx.compose.foundation.clickable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextStyle + +@Composable +fun Link( + modifier: Modifier = Modifier, + textDecoration: String, + url: String, + color: Color, + typography: TextStyle +) { + val uriHandler = LocalUriHandler.current + + Text( + modifier = modifier.clickable { uriHandler.openUri(url) }, + text = textDecoration, + color = color, + typography = typography.copy(color = color) + ) +} + +@Composable +fun Link( + modifier: Modifier = Modifier, + textDecoration: AnnotatedString, + url: String, + color: Color, + typography: TextStyle +) { + val uriHandler = LocalUriHandler.current + + Text( + modifier = modifier.clickable { uriHandler.openUri(url) }, + text = textDecoration, + color = color, + typography = typography.copy(color = color) + ) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Link.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Link.kt new file mode 100644 index 000000000..76a9a9bf0 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Link.kt @@ -0,0 +1,55 @@ +package com.atls.hyperion.ui.primitives.stories + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.ui.primitives.Link +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.colors.Colors +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.typography.FontSize +import com.atls.hyperion.ui.theme.typography.LineHeights + +class LinkStory : ComponentExample { + override val name: String = "Link" + + @Composable + override fun Content() { + Column( + modifier = Modifier.padding(Space.g16) + ) { + Link( + textDecoration = "Standard Blue Link", + url = "https://google.com", + color = Colors.Text.blue, + typography = TextStyle( + fontSize = FontSize.md, + lineHeight = LineHeights.md + ) + ) + VerticalSpacer(Space.g12) + Link( + textDecoration = "Soft Blue Link", + url = "https://google.com", + color = Colors.Text.softBlue, + typography = TextStyle( + fontSize = FontSize.md, + lineHeight = LineHeights.md + ) + ) + VerticalSpacer(Space.g12) + Link( + textDecoration = "Small Gray Link", + url = "https://google.com", + color = Colors.Text.gray, + typography = TextStyle( + fontSize = FontSize.xs, + lineHeight = LineHeights.xs + ) + ) + } + } +} From eaef57bcb829b45c0461c597fcdfb1b9bef64749 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:54:10 +0300 Subject: [PATCH 33/75] feat(ui): text component --- .../com/atls/hyperion/ui/primitives/Text.kt | 52 ++++++++++++++++ .../hyperion/ui/primitives/stories/Text.kt | 61 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Text.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Text.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Text.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Text.kt new file mode 100644 index 000000000..67aaece8b --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Text.kt @@ -0,0 +1,52 @@ +package com.atls.hyperion.ui.primitives + +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow + +@Composable +fun Text( + modifier: Modifier = Modifier, + text: String, + color: Color, + typography: TextStyle, + maxLines: Int = Int.MAX_VALUE, + overflow: TextOverflow = TextOverflow.Ellipsis, + textAlign: TextAlign? = null +) { + Text( + modifier = modifier, + text = text, + color = color, + style = typography, + overflow = overflow, + maxLines = maxLines, + textAlign = textAlign + ) +} + +@Composable +fun Text( + modifier: Modifier = Modifier, + text: AnnotatedString, + color: Color, + typography: TextStyle, + maxLines: Int = Int.MAX_VALUE, + overflow: TextOverflow = TextOverflow.Ellipsis, + textAlign: TextAlign? = null +) { + Text( + modifier = modifier, + text = text, + color = color, + style = typography, + overflow = overflow, + maxLines = maxLines, + textAlign = textAlign + ) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Text.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Text.kt new file mode 100644 index 000000000..f3e878db8 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/stories/Text.kt @@ -0,0 +1,61 @@ +package com.atls.hyperion.ui.primitives.stories + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.ui.primitives.Text +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.colors.Colors +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.typography.FontSize +import com.atls.hyperion.ui.theme.typography.LineHeights + +class TextStory : ComponentExample { + override val name: String = "Text" + + @Composable + override fun Content() { + Column( + modifier = Modifier.padding(Space.g16) + ) { + Text( + text = "Heading XL", + color = Colors.Text.black, + typography = TextStyle( + fontSize = FontSize.xl4, + lineHeight = LineHeights.xl4 + ) + ) + VerticalSpacer(Space.g12) + Text( + text = "Body Medium", + color = Colors.Text.almostBlack, + typography = TextStyle( + fontSize = FontSize.md, + lineHeight = LineHeights.md + ) + ) + VerticalSpacer(Space.g12) + Text( + text = "Small Caption", + color = Colors.Text.gray, + typography = TextStyle( + fontSize = FontSize.xs, + lineHeight = LineHeights.xs + ) + ) + VerticalSpacer(Space.g12) + Text( + text = "Error Text", + color = Colors.Text.red, + typography = TextStyle( + fontSize = FontSize.sm, + lineHeight = LineHeights.sm + ) + ) + } + } +} From d04a833915ab0a1274653c26c6c6ee2ff55f7b31 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:54:36 +0300 Subject: [PATCH 34/75] feat(theme): checkbox and image sizes --- .../hyperion/ui/theme/tokens/components/CheckboxSize.kt | 9 +++++++++ .../hyperion/ui/theme/tokens/components/ImageSize.kt | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/CheckboxSize.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/ImageSize.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/CheckboxSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/CheckboxSize.kt new file mode 100644 index 000000000..b487fc00b --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/CheckboxSize.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.theme.tokens.components + +import androidx.compose.ui.unit.dp + +object CheckboxSize { + val large = 32.dp + val medium = 24.dp + val small = 16.dp +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/ImageSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/ImageSize.kt new file mode 100644 index 000000000..4467d79de --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/ImageSize.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.theme.tokens.components + +import androidx.compose.ui.unit.dp + +object ImageSize { + val huge = 58.dp + val large = 48.dp + val medium = 40.dp +} From bc068169301d93e219093e2d2c65c97dc85be469 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Sat, 10 Jan 2026 04:55:22 +0300 Subject: [PATCH 35/75] feat(common): ktor engine deps --- mobile/kmp/.junie/guidelines.md | 63 ---------------------------- mobile/kmp/gradle/libs.versions.toml | 6 +++ mobile/kmp/ui/build.gradle.kts | 18 +++++++- 3 files changed, 22 insertions(+), 65 deletions(-) delete mode 100644 mobile/kmp/.junie/guidelines.md diff --git a/mobile/kmp/.junie/guidelines.md b/mobile/kmp/.junie/guidelines.md deleted file mode 100644 index 2096c7be5..000000000 --- a/mobile/kmp/.junie/guidelines.md +++ /dev/null @@ -1,63 +0,0 @@ -# Project Guidelines - -## Scope -- Репозиторий — **многомодульный Android‑проект** на Kotlin. -- Цель изменений — расширение функциональности без нарушения существующих контрактов. -- Архитектура базируется на принципах **FSD (Feature‑Sliced Design)**, адаптированных под мобильную разработку. - -## Структура проекта -- Gradle multi‑module: `:app`, `:features:*`, `:ui`, `:shared`, `:navigation`. -- Build Tool: **Gradle 8+** с использованием **Kotlin DSL** (`build.gradle.kts`). -- Convention Plugins используются для переиспользования конфигураций, зависимостей и версий. - -## Архитектура -- **Feature‑Sliced Design (FSD)** - - Код во фичах делится на FSD‑слои: `screens` (Pages), `fragments` (Widgets/Features), `entities`, `shared`, `app`. - - **Screens**: основные пользовательские точки входа (экраны). - - **Fragments**: переиспользуемые UI‑блоки фичи (аналог Widget/Feature UI сегментов в FSD). - - **Entities**: модели, константы, API/мапперы, относящиеся к фиче. - - **Shared**: утилиты и ошибки, специфичные для фичи (shared‑код на уровне фичи). - - **App**: DI и навигация фичи. - - Зависимости строго направленные: `screens` → `fragments` → `entities` → `shared`. - - Нельзя делать циклические или горизонтальные импорты между фичами/срезами. -- **DI (Dependency Injection)**: строго через **Koin**. -- **Сетевой слой**: основа — **Apollo GraphQL**; REST допустим только для медиа или сторонних интеграций. -- **UI**: Jetpack Compose - -## Новые модули (Features) -- Каждый новый модуль в `features/` обязан: - - Иметь чёткую область ответственности. - - Следовать **FSD‑правилам** разделения на слои. - - Использовать существующие UI‑примитивы из `:ui` и `:shared-ui`. - - Подключаться в `settings.gradle.kts` или `gradleSettings/modules.gradle.kts` (если используется) через `:features:` - -## Тесты -- Используется **Kotlin tests** (`kotlin.test`) как основной фреймворк для модульных тестов в KMM/Kotlin. -- Покрытие рекомендуется для логики внутри фич. -- Перед финальной сборкой: - - Проект должен успешно собираться (`./gradlew assembleDebug` / `assembleRelease`). - - Все тесты должны проходить. - -## Code Style -- **Магические значения** выносить в константы (например, в `config/Constants.kt`). -- **Повторяющийся код** выносить в отдельные функции/методы. -- **Один класс/функция — один файл**; не держать несколько функций/классов в одном файле. -- **Плоские нейминги:** если путь уже содержит название фичи/контекста, **не дублировать его в имени файла**. - Например, `features/profile/fragments/editing/Fragment.kt` — файл просто `Fragment.kt`. -- **Не писать комментарии в коде.** -- **Логировать можно только при дебаге.** -- Строки должны быть в `strings.xml`. -- Цвета и шрифты должны браться строго из темы (`ui/theme/Theme.kt`). -- Имена файлов начинаются строго с большой буквы - -## Что запрещено -- Ломать публичные API существующих модулей. -- Добавлять тяжёлые зависимости без согласования. -- Игнорировать **FSD‑правила** зависимостей. -- Смешивать логику между модулями напрямую — использовать API. - -## Поведение Junie -1. **Анализ**: сначала изучить структуру аналогичных фич. -2. **Минимализм**: вносить только необходимые изменения. -3. **Аргументация**: объяснять архитектурные изменения. -4. **Тестирование**: после выполнения задачи собирать проект и прогонять тесты diff --git a/mobile/kmp/gradle/libs.versions.toml b/mobile/kmp/gradle/libs.versions.toml index 2d63e3dd1..9552d8258 100644 --- a/mobile/kmp/gradle/libs.versions.toml +++ b/mobile/kmp/gradle/libs.versions.toml @@ -1,13 +1,19 @@ [versions] kotlin = "2.2.0" +ktor = "3.3.1" compose = "1.10.0-rc02" composeShadow = "2.0.4" +coilCompose = "3.3.0" agp = "8.9.0" androidx-activityCompose = "1.9.3" [libraries] androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } compose-shadow = { module = "com.adamglin:compose-shadow", version.ref = "composeShadow" } +coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" } +coil-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coilCompose" } +ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } +ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } [plugins] kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } diff --git a/mobile/kmp/ui/build.gradle.kts b/mobile/kmp/ui/build.gradle.kts index 6b5b6adf3..06e228750 100644 --- a/mobile/kmp/ui/build.gradle.kts +++ b/mobile/kmp/ui/build.gradle.kts @@ -16,7 +16,7 @@ kotlin { jvmTarget.set(JvmTarget.JVM_21) } } - + listOf( iosX64(), iosArm64(), @@ -27,7 +27,7 @@ kotlin { isStatic = true } } - + sourceSets { commonMain.dependencies { api(project(":storybook")) @@ -38,6 +38,20 @@ kotlin { implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) implementation(libs.compose.shadow) + implementation(libs.coil.compose) + implementation(libs.coil.network.ktor) + } + + androidMain { + dependencies { + implementation(libs.ktor.client.okhttp) + } + } + + iosMain { + dependencies { + implementation(libs.ktor.client.darwin) + } } } } From ee9b93f76c02fd90f55aeeda0776dddefcb84bf7 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 22:31:54 +0300 Subject: [PATCH 36/75] refactor(common): use theme transparent color --- .../avatar/styles/appearance/Variants.kt | 6 +-- .../hyperion/ui/components/button/Layout.kt | 6 +-- .../button/styles/appearance/Colors.kt | 7 +-- .../card/style/appearance/Appearance.kt | 3 +- .../checkbox/styles/appearance/Colors.kt | 3 +- .../checkbox/styles/appearance/Variants.kt | 54 +++++++++---------- .../hyperion/ui/theme/tokens/colors/Colors.kt | 1 + 7 files changed, 42 insertions(+), 38 deletions(-) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt index b960cbac7..c5f3e7b82 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/appearance/Variants.kt @@ -1,11 +1,11 @@ package com.atls.hyperion.ui.components.avatar.styles.appearance import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors @Composable fun AvatarAppearance.Companion.default(): AvatarAppearance = AvatarAppearance( - backgroundColor = Color.Transparent, - borderColor = Color.Transparent + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.transparent ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt index 150e7c267..5e41c0509 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt @@ -16,7 +16,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Color import com.atls.hyperion.ui.components.button.locals.LocalState import com.atls.hyperion.ui.components.button.state.ButtonState import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance @@ -25,6 +24,7 @@ import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape import com.atls.hyperion.ui.shared.addon.AddonPosition import com.atls.hyperion.ui.shared.addon.AddonSlotManager import com.atls.hyperion.ui.theme.tokens.Elevation +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors @OptIn(ExperimentalMaterialApi::class) @Composable @@ -57,12 +57,12 @@ fun ButtonLayout( colors = ButtonDefaults.buttonColors( backgroundColor = when (colors) { is Colors.Solid -> colors.backgroundColor - is Colors.Gradient -> Color.Transparent + is Colors.Gradient -> ThemeColors.Palette.transparent }, contentColor = colors.textColor, disabledBackgroundColor = when (colors) { is Colors.Solid -> colors.backgroundColor - is Colors.Gradient -> Color.Transparent + is Colors.Gradient -> ThemeColors.Palette.transparent }, disabledContentColor = colors.textColor ), diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Colors.kt index ff1a1719d..f7a6998ed 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Colors.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Colors.kt @@ -2,20 +2,21 @@ package com.atls.hyperion.ui.components.button.styles.appearance import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors sealed class Colors( val textColor: Color, - val borderColor: Color = Color.Transparent + val borderColor: Color = ThemeColors.Palette.transparent ) { class Solid( val backgroundColor: Color, textColor: Color, - borderColor: Color = Color.Transparent + borderColor: Color = ThemeColors.Palette.transparent ) : Colors(textColor, borderColor) class Gradient( val backgroundBrush: Brush, textColor: Color, - borderColor: Color = Color.Transparent + borderColor: Color = ThemeColors.Palette.transparent ) : Colors(textColor, borderColor) } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt index f07f4a2f2..8af36bcc7 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt @@ -3,10 +3,11 @@ package com.atls.hyperion.ui.components.card.style.appearance import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp import com.atls.hyperion.ui.theme.tokens.Elevation +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors data class CardAppearance( val backgroundColor: Color, - val borderColor: Color = Color.Transparent, + val borderColor: Color = ThemeColors.Palette.transparent, val elevation: Dp = Elevation.zero ) { companion object diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt index 04fc113e1..1c59d8ea2 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Colors.kt @@ -1,9 +1,10 @@ package com.atls.hyperion.ui.components.checkbox.styles.appearance import androidx.compose.ui.graphics.Color +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors data class Colors( val backgroundColor: Color, - val borderColor: Color = Color.Transparent, + val borderColor: Color = ThemeColors.Palette.transparent, val checkColor: Color ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt index fa39a42e5..1b8cca409 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/appearance/Variants.kt @@ -5,56 +5,56 @@ import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors fun CheckboxAppearance.Companion.blue(): CheckboxAppearance = CheckboxAppearance( default = Colors( - backgroundColor = ThemeColors.Checkbox.Blue.Default.background, - borderColor = ThemeColors.Checkbox.Blue.Default.border, - checkColor = ThemeColors.Checkbox.Blue.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.blue, + checkColor = ThemeColors.Palette.blue ), checked = Colors( - backgroundColor = ThemeColors.Checkbox.Blue.Default.background, - borderColor = ThemeColors.Checkbox.Blue.Default.border, - checkColor = ThemeColors.Checkbox.Blue.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.blue, + checkColor = ThemeColors.Palette.blue ), disabled = Colors( - backgroundColor = ThemeColors.Checkbox.Blue.Default.background, - borderColor = ThemeColors.Checkbox.Blue.Default.border, - checkColor = ThemeColors.Checkbox.Blue.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.blue, + checkColor = ThemeColors.Palette.blue ) ) fun CheckboxAppearance.Companion.green(): CheckboxAppearance = CheckboxAppearance( default = Colors( - backgroundColor = ThemeColors.Checkbox.Green.Default.background, - borderColor = ThemeColors.Checkbox.Green.Default.border, - checkColor = ThemeColors.Checkbox.Green.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.green, + checkColor = ThemeColors.Palette.green ), checked = Colors( - backgroundColor = ThemeColors.Checkbox.Green.Default.background, - borderColor = ThemeColors.Checkbox.Green.Default.border, - checkColor = ThemeColors.Checkbox.Green.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.green, + checkColor = ThemeColors.Palette.green ), disabled = Colors( - backgroundColor = ThemeColors.Checkbox.Green.Default.background, - borderColor = ThemeColors.Checkbox.Green.Default.border, - checkColor = ThemeColors.Checkbox.Green.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.green, + checkColor = ThemeColors.Palette.green ) ) fun CheckboxAppearance.Companion.red(): CheckboxAppearance = CheckboxAppearance( default = Colors( - backgroundColor = ThemeColors.Checkbox.Red.Default.background, - borderColor = ThemeColors.Checkbox.Red.Default.border, - checkColor = ThemeColors.Checkbox.Red.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.red, + checkColor = ThemeColors.Palette.red ), checked = Colors( - backgroundColor = ThemeColors.Checkbox.Red.Default.background, - borderColor = ThemeColors.Checkbox.Red.Default.border, - checkColor = ThemeColors.Checkbox.Red.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.red, + checkColor = ThemeColors.Palette.red ), disabled = Colors( - backgroundColor = ThemeColors.Checkbox.Red.Default.background, - borderColor = ThemeColors.Checkbox.Red.Default.border, - checkColor = ThemeColors.Checkbox.Red.Default.font + backgroundColor = ThemeColors.Palette.transparent, + borderColor = ThemeColors.Palette.red, + checkColor = ThemeColors.Palette.red ) ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Colors.kt index 760ba665c..0486fded9 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Colors.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Colors.kt @@ -13,6 +13,7 @@ object Colors { val black = Color(0xFF000000) val blackThreeQuarters = Color(0xBF000000) val lightPurple = Color(0xFFDADEED) + val transparent = Color.Transparent } object Text { From 5644f2ad270830131428b1b2a9bcce06d13fc88b Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 22:38:31 +0300 Subject: [PATCH 37/75] chore(sample): new components story usage --- .../kotlin/com/atls/hyperion/sample/App.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt index b0a3004bd..4678edce3 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt @@ -3,15 +3,30 @@ package com.atls.hyperion.sample import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import com.atls.hyperion.storybook.fragments.storybook.Storybook -import com.atls.hyperion.ui.components.button.stories.ButtonExample +import com.atls.hyperion.ui.components.avatar.stories.AvatarStory +import com.atls.hyperion.ui.components.button.stories.ButtonStory +import com.atls.hyperion.ui.components.card.stories.CardStory +import com.atls.hyperion.ui.components.checkbox.stories.CheckboxStory +import com.atls.hyperion.ui.components.divider.stories.DividerStory +import com.atls.hyperion.ui.components.input.stories.InputStory +import com.atls.hyperion.ui.components.switch.stories.SwitchStory +import com.atls.hyperion.ui.primitives.stories.LinkStory +import com.atls.hyperion.ui.primitives.stories.TextStory @Composable fun App() { MaterialTheme { Storybook( components = listOf( - ButtonExample(), - ButtonExample() + AvatarStory(), + ButtonStory(), + CheckboxStory(), + DividerStory(), + InputStory(), + SwitchStory(), + CardStory(), + TextStory(), + LinkStory() ) ) } From 438c709a4fd4c376268dffac11072f46f48e7d0f Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 22:49:19 +0300 Subject: [PATCH 38/75] feat(ui): input styles --- .../input/style/appearance/Appearance.kt | 24 ++++++++++++ .../input/style/appearance/Colors.kt | 20 ++++++++++ .../input/style/appearance/Variants.kt | 26 +++++++++++++ .../ui/components/input/style/shape/Shape.kt | 16 ++++++++ .../components/input/style/shape/Variants.kt | 38 +++++++++++++++++++ 5 files changed, 124 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Colors.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Appearance.kt new file mode 100644 index 000000000..155d9c6dd --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Appearance.kt @@ -0,0 +1,24 @@ +package com.atls.hyperion.ui.components.input.style.appearance + +import com.atls.hyperion.ui.components.input.state.InputState + +data class InputAppearance( + val default: Colors, + val filled: Colors, + val focused: Colors, + val disabled: Colors, + val error: Colors, + val active: Colors +) { + companion object Companion + + fun getColorsFromState(state: InputState): Colors = + when (state) { + InputState.Default -> default + InputState.Disabled -> disabled + InputState.Error -> error + InputState.Filled -> filled + InputState.Focused -> focused + InputState.Active -> active + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Colors.kt new file mode 100644 index 000000000..9397dd7c5 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Colors.kt @@ -0,0 +1,20 @@ +package com.atls.hyperion.ui.components.input.style.appearance + +import androidx.compose.ui.graphics.Color +import com.atls.hyperion.ui.theme.tokens.colors.ColorSet +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors + +data class Colors( + val backgroundColor: Color, + val textColor: Color, + val borderColor: Color = ThemeColors.Palette.transparent, + val cursorColor: Color = textColor +) { + companion object { + fun fromColorSet(colorSet: ColorSet): Colors = Colors( + backgroundColor = colorSet.background, + textColor = colorSet.font, + borderColor = colorSet.border + ) + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt new file mode 100644 index 000000000..5c64c68ed --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt @@ -0,0 +1,26 @@ +package com.atls.hyperion.ui.components.input.style.appearance + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.colors.Colors as TokenColors + +@Composable +fun InputAppearance.Companion.blue(): InputAppearance = + InputAppearance( + default = Colors.fromColorSet(TokenColors.Input.Blue.Default), + filled = Colors.fromColorSet(TokenColors.Input.Blue.Default), + focused = Colors.fromColorSet(TokenColors.Input.Blue.Focus), + disabled = Colors.fromColorSet(TokenColors.Input.Blue.Disabled), + error = Colors.fromColorSet(TokenColors.Input.Blue.Default), // TODO: Add error colors to tokens + active = Colors.fromColorSet(TokenColors.Input.Blue.Active) + ) + +@Composable +fun InputAppearance.Companion.white(): InputAppearance = + InputAppearance( + default = Colors.fromColorSet(TokenColors.Input.White.Default), + filled = Colors.fromColorSet(TokenColors.Input.White.Default), + focused = Colors.fromColorSet(TokenColors.Input.White.Focus), + disabled = Colors.fromColorSet(TokenColors.Input.White.Disabled), + error = Colors.fromColorSet(TokenColors.Input.White.Default), // TODO: Add error colors to tokens + active = Colors.fromColorSet(TokenColors.Input.White.Active) + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Shape.kt new file mode 100644 index 000000000..daab415a8 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Shape.kt @@ -0,0 +1,16 @@ +package com.atls.hyperion.ui.components.input.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.theme.tokens.layout.Space + +data class InputShape( + val cornerRadius: Dp, + val borderStroke: Dp, + val paddings: PaddingValues, + val textPaddings: PaddingValues = PaddingValues(Space.zero), + val typography: TextStyle +) { + companion object Companion +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Variants.kt new file mode 100644 index 000000000..504233cea --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/shape/Variants.kt @@ -0,0 +1,38 @@ +package com.atls.hyperion.ui.components.input.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.typography.FontSize + +@Composable +fun InputShape.Companion.large(): InputShape = + InputShape( + cornerRadius = CornerRadius.md, + borderStroke = BorderStroke.tiny, + paddings = PaddingValues( + vertical = Space.g12, + horizontal = Space.g16 + ), + textPaddings = PaddingValues(Space.zero), + typography = TextStyle(fontSize = FontSize.md) + ) + +@Composable +fun InputShape.Companion.normal(): InputShape = + InputShape( + cornerRadius = CornerRadius.xs3, + borderStroke = BorderStroke.tiny, + paddings = PaddingValues( + vertical = Space.g8, + horizontal = Space.g12 + ), + textPaddings = PaddingValues( + vertical = Space.g4, + horizontal = Space.zero + ), + typography = TextStyle(fontSize = FontSize.sm) + ) From 0d651efcfe850344a79a22e7c2d2e837b9a7519a Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 22:49:40 +0300 Subject: [PATCH 39/75] feat(ui): input locals --- .../ui/components/input/locals/LocalAppearance.kt | 8 ++++++++ .../hyperion/ui/components/input/locals/LocalState.kt | 8 ++++++++ .../hyperion/ui/components/input/state/InputState.kt | 10 ++++++++++ 3 files changed, 26 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalAppearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalState.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/state/InputState.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalAppearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalAppearance.kt new file mode 100644 index 000000000..3203205af --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalAppearance.kt @@ -0,0 +1,8 @@ +package com.atls.hyperion.ui.components.input.locals + +import androidx.compose.runtime.compositionLocalOf +import com.atls.hyperion.ui.components.input.style.appearance.InputAppearance + +val LocalAppearance = compositionLocalOf { + error("InputAppearance not provided") +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalState.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalState.kt new file mode 100644 index 000000000..70e3ac986 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/locals/LocalState.kt @@ -0,0 +1,8 @@ +package com.atls.hyperion.ui.components.input.locals + +import androidx.compose.runtime.compositionLocalOf +import com.atls.hyperion.ui.components.input.state.InputState + +val LocalState = compositionLocalOf { + error("InputState not provided") +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/state/InputState.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/state/InputState.kt new file mode 100644 index 000000000..8d53590f6 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/state/InputState.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.components.input.state + +sealed interface InputState { + data object Default : InputState + data object Focused : InputState + data object Filled : InputState + data object Disabled : InputState + data object Error : InputState + data object Active : InputState +} From 25c578614004dcfd762b7d99cf5acb7bc046ac84 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 22:50:14 +0300 Subject: [PATCH 40/75] feat(ui): input component --- .../hyperion/ui/components/input/Input.kt | 86 +++++++++++++++++ .../input/container/InputContainer.kt | 76 +++++++++++++++ .../input/placeholder/InputPlaceholder.kt | 24 +++++ .../ui/components/input/stories/Component.kt | 94 +++++++++++++++++++ 4 files changed, 280 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/Input.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/container/InputContainer.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/placeholder/InputPlaceholder.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/stories/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/Input.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/Input.kt new file mode 100644 index 000000000..fb0fcaa94 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/Input.kt @@ -0,0 +1,86 @@ +package com.atls.hyperion.ui.components.input + +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsFocusedAsState +import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation +import com.atls.hyperion.ui.components.input.container.InputContainer +import com.atls.hyperion.ui.components.input.state.InputState +import com.atls.hyperion.ui.components.input.style.appearance.InputAppearance +import com.atls.hyperion.ui.components.input.style.shape.InputShape +import com.atls.hyperion.ui.shared.addon.AddonSlotManager +import com.atls.hyperion.ui.theme.tokens.layout.Weight +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors + +@Composable +fun Input( + modifier: Modifier = Modifier, + value: TextFieldValue, + onValueChange: (TextFieldValue) -> Unit, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + isError: Boolean = false, + enabled: Boolean = true, + readOnly: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + appearance: InputAppearance, + shape: InputShape, + visualTransformation: VisualTransformation = VisualTransformation.None, + addons: AddonSlotManager = AddonSlotManager(), + placeholder: @Composable (() -> Unit)? = null, +) { + val isFocused = interactionSource.collectIsFocusedAsState().value + val isPressed = interactionSource.collectIsPressedAsState().value + + val currentState = when { + !enabled -> InputState.Disabled + isError -> InputState.Error + isPressed -> InputState.Active + isFocused -> InputState.Focused + value.text.isNotEmpty() -> InputState.Filled + else -> InputState.Default + } + + val colors = appearance.getColorsFromState(currentState) + + InputContainer( + modifier = modifier, + appearance = appearance, + shape = shape, + state = currentState, + addons = addons + ) { + BasicTextField( + value = value, + onValueChange = onValueChange, + enabled = enabled, + readOnly = readOnly, + interactionSource = interactionSource, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + cursorBrush = SolidColor(colors.cursorColor), + textStyle = shape.typography.copy(color = colors.textColor), + visualTransformation = visualTransformation, + decorationBox = { innerTextField -> + if (value.text.isEmpty() && placeholder != null) { + placeholder() + } + innerTextField() + }, + modifier = Modifier + .background(ThemeColors.Palette.transparent) + .padding(shape.textPaddings) + .weight(Weight.full) + ) + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/container/InputContainer.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/container/InputContainer.kt new file mode 100644 index 000000000..e6de4f7ad --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/container/InputContainer.kt @@ -0,0 +1,76 @@ +package com.atls.hyperion.ui.components.input.container + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsFocusedAsState +import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.input.locals.LocalAppearance +import com.atls.hyperion.ui.components.input.locals.LocalState +import com.atls.hyperion.ui.components.input.state.InputState +import com.atls.hyperion.ui.components.input.style.appearance.InputAppearance +import com.atls.hyperion.ui.components.input.style.appearance.blue +import com.atls.hyperion.ui.components.input.style.shape.InputShape +import com.atls.hyperion.ui.components.input.style.shape.normal +import com.atls.hyperion.ui.shared.addon.AddonPosition +import com.atls.hyperion.ui.shared.addon.AddonSlotManager + +@Composable +fun InputContainer( + modifier: Modifier = Modifier, + appearance: InputAppearance = InputAppearance.blue(), + shape: InputShape = InputShape.normal(), + state: InputState? = null, + addons: AddonSlotManager = AddonSlotManager(), + content: @Composable RowScope.(interactionSource: MutableInteractionSource) -> Unit +) { + val interactionSource = remember { MutableInteractionSource() } + val isFocused = interactionSource.collectIsFocusedAsState().value + val isPressed = interactionSource.collectIsPressedAsState().value + + val resolvedState = state ?: when { + isPressed -> InputState.Active + isFocused -> InputState.Focused + else -> InputState.Default + } + + val colors = appearance.getColorsFromState(resolvedState) + + CompositionLocalProvider( + LocalState provides resolvedState, + LocalAppearance provides appearance + ) { + Row( + modifier = modifier + .border( + width = shape.borderStroke, + color = colors.borderColor, + shape = RoundedCornerShape(shape.cornerRadius) + ) + .background(colors.backgroundColor, RoundedCornerShape(shape.cornerRadius)) + .padding(shape.paddings), + verticalAlignment = Alignment.CenterVertically + ) { + addons.get(AddonPosition.Before).forEach { + it.Content() + it.Spacer() + } + + content(interactionSource) + + addons.get(AddonPosition.After).forEach { + it.Spacer() + it.Content() + } + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/placeholder/InputPlaceholder.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/placeholder/InputPlaceholder.kt new file mode 100644 index 000000000..9bc572171 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/placeholder/InputPlaceholder.kt @@ -0,0 +1,24 @@ +package com.atls.hyperion.ui.components.input.placeholder + +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.input.style.appearance.InputAppearance +import com.atls.hyperion.ui.components.input.style.appearance.blue +import com.atls.hyperion.ui.components.input.style.shape.InputShape +import com.atls.hyperion.ui.components.input.style.shape.normal + +@Composable +fun InputPlaceholder( + modifier: Modifier = Modifier, + text: String, + appearance: InputAppearance = InputAppearance.blue(), + shape: InputShape = InputShape.normal() +) { + Text( + modifier = modifier, + text = text, + color = appearance.default.textColor, + style = shape.typography + ) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/stories/Component.kt new file mode 100644 index 000000000..e2ee2c9f0 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/stories/Component.kt @@ -0,0 +1,94 @@ +package com.atls.hyperion.ui.components.input.stories + +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.material.Switch +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.TextFieldValue +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.components.input.Input +import com.atls.hyperion.ui.components.input.placeholder.InputPlaceholder +import com.atls.hyperion.ui.components.input.style.appearance.InputAppearance +import com.atls.hyperion.ui.components.input.style.appearance.blue +import com.atls.hyperion.ui.components.input.style.appearance.white +import com.atls.hyperion.ui.components.input.style.shape.InputShape +import com.atls.hyperion.ui.components.input.style.shape.large +import com.atls.hyperion.ui.components.input.style.shape.normal +import com.atls.hyperion.ui.primitives.HorizontalSpacer +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.tokens.layout.Weight + +class InputStory : ComponentExample { + override val name: String = "Input" + + @Composable + override fun Content() { + var enabled by remember { mutableStateOf(true) } + var isError by remember { mutableStateOf(false) } + var textValue by remember { mutableStateOf(TextFieldValue("")) } + + Column { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = Space.g12), + verticalAlignment = Alignment.CenterVertically + ) { + Text(modifier = Modifier.weight(Weight.full), text = "Enabled") + HorizontalSpacer(Space.g12) + Switch(checked = enabled, onCheckedChange = { enabled = it }) + } + VerticalSpacer(Space.g8) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = Space.g12), + verticalAlignment = Alignment.CenterVertically + ) { + Text(modifier = Modifier.weight(Weight.full), text = "Error") + HorizontalSpacer(Space.g12) + Switch(checked = isError, onCheckedChange = { isError = it }) + } + VerticalSpacer(Space.g12) + + ComponentVariants( + name = "Input", + appearances = listOf( + "Blue" to { InputAppearance.blue() }, + "White" to { InputAppearance.white() } + ), + shapes = listOf( + "Large" to { InputShape.large() }, + "Normal" to { InputShape.normal() } + ) + ) { appearance: InputAppearance, shape: InputShape -> + Input( + value = textValue, + onValueChange = { textValue = it }, + appearance = appearance, + shape = shape, + enabled = enabled, + isError = isError, + placeholder = { + InputPlaceholder( + text = "Placeholder", + appearance = appearance, + shape = shape + ) + } + ) + } + } + } +} From 4fa29c243cfbf7bc9d8e42020fe408eddbdafd71 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 22:54:35 +0300 Subject: [PATCH 41/75] feat(theme): alpha tokens --- .../com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt new file mode 100644 index 000000000..ae0441a7a --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt @@ -0,0 +1,7 @@ +package com.atls.hyperion.ui.theme.tokens.colors + +object Alpha { + val huge = 0.9f + val large = 0.8f + val medium = 0.6f +} From 2a026a31173d38f8309250731270798c731c35bc Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 23:10:26 +0300 Subject: [PATCH 42/75] feat(ui): switch styles --- .../switch/styles/appearance/Appearance.kt | 19 +++++++++++++++++++ .../switch/styles/appearance/Colors.kt | 10 ++++++++++ .../switch/styles/appearance/Variants.kt | 19 +++++++++++++++++++ .../components/switch/styles/shape/Shape.kt | 12 ++++++++++++ .../switch/styles/shape/Variants.kt | 12 ++++++++++++ .../ui/theme/tokens/components/SwitchSize.kt | 9 +++++++++ 6 files changed, 81 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Colors.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/SwitchSize.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Appearance.kt new file mode 100644 index 000000000..d2dc4a8d0 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Appearance.kt @@ -0,0 +1,19 @@ +package com.atls.hyperion.ui.components.switch.styles.appearance + +import com.atls.hyperion.ui.components.switch.state.SwitchState + +data class SwitchAppearance( + val default: Colors, + val checked: Colors = default, + val disabled: Colors = default +) { + fun fromState(state: SwitchState): Colors { + return when (state) { + SwitchState.Default -> default + SwitchState.Checked -> checked + SwitchState.Disabled -> disabled + } + } + + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Colors.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Colors.kt new file mode 100644 index 000000000..75eac9fac --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Colors.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.components.switch.styles.appearance + +import androidx.compose.ui.graphics.Color + +data class Colors( + val trackColor: Color, + val trackBorderColor: Color, + val thumbColor: Color, + val thumbBorderColor: Color, +) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Variants.kt new file mode 100644 index 000000000..b61709f33 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/appearance/Variants.kt @@ -0,0 +1,19 @@ +package com.atls.hyperion.ui.components.switch.styles.appearance + +import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors + +fun SwitchAppearance.Companion.default(): SwitchAppearance = + SwitchAppearance( + default = Colors( + trackColor = ThemeColors.Palette.transparent, + trackBorderColor = ThemeColors.Palette.blue, + thumbColor = ThemeColors.Palette.blue, + thumbBorderColor = ThemeColors.Palette.blue + ), + disabled = Colors( + trackColor = ThemeColors.Palette.transparent, + trackBorderColor = ThemeColors.Palette.blue, + thumbColor = ThemeColors.Palette.transparent, + thumbBorderColor = ThemeColors.Palette.blue + ) + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Shape.kt new file mode 100644 index 000000000..dec93f9d9 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Shape.kt @@ -0,0 +1,12 @@ +package com.atls.hyperion.ui.components.switch.styles.shape + +import androidx.compose.ui.unit.Dp + +data class SwitchShape( + val trackWidth: Dp, + val trackHeight: Dp, + val thumbSize: Dp, + val thumbPadding: Dp +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt new file mode 100644 index 000000000..15e5b743a --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt @@ -0,0 +1,12 @@ +package com.atls.hyperion.ui.components.switch.styles.shape + +import com.atls.hyperion.ui.theme.tokens.components.SwitchSize +import com.atls.hyperion.ui.theme.tokens.layout.Space + +fun SwitchShape.Companion.medium(): SwitchShape = + SwitchShape( + trackWidth = SwitchSize.defaultWidth, + trackHeight = SwitchSize.defaultHeight, + thumbSize = SwitchSize.defaultTrackSize, + thumbPadding = Space.g2 + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/SwitchSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/SwitchSize.kt new file mode 100644 index 000000000..72132862e --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/SwitchSize.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.theme.tokens.components + +import androidx.compose.ui.unit.dp + +object SwitchSize { + val defaultWidth = 44.dp + val defaultHeight = 22.dp + val defaultTrackSize = 18.dp +} From 3888d583cff6212cabf0f0851131d18ee251b0e3 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Mon, 12 Jan 2026 23:10:43 +0300 Subject: [PATCH 43/75] feat(ui): switch component --- .../hyperion/ui/components/switch/Switch.kt | 80 +++++++++++++++++++ .../ui/components/switch/state/SwitchState.kt | 7 ++ .../ui/components/switch/stories/Component.kt | 69 ++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/Switch.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/state/SwitchState.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/stories/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/Switch.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/Switch.kt new file mode 100644 index 000000000..32c7d9df1 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/Switch.kt @@ -0,0 +1,80 @@ +package com.atls.hyperion.ui.components.switch + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +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.unit.dp +import com.atls.hyperion.ui.components.switch.state.SwitchState +import com.atls.hyperion.ui.components.switch.styles.appearance.SwitchAppearance +import com.atls.hyperion.ui.components.switch.styles.appearance.default +import com.atls.hyperion.ui.components.switch.styles.shape.SwitchShape +import com.atls.hyperion.ui.components.switch.styles.shape.medium + +@Composable +fun Switch( + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, + disabled: Boolean = false, + appearance: SwitchAppearance = SwitchAppearance.default(), + shape: SwitchShape = SwitchShape.medium(), +) { + val state = remember(checked, disabled) { + if (disabled) { + SwitchState.Disabled + } else { + if (checked) SwitchState.Checked else SwitchState.Default + } + } + + val colors = appearance.fromState(state) + + val thumbOffset by animateDpAsState( + targetValue = if (checked) shape.trackWidth - shape.thumbSize - shape.thumbPadding else shape.thumbPadding + ) + + Box( + modifier = modifier + .size(width = shape.trackWidth, height = shape.trackHeight) + .clip(RoundedCornerShape(shape.trackHeight / 2)) + .background(colors.trackColor) + .border( + width = 1.dp, + color = colors.trackBorderColor, + shape = RoundedCornerShape(shape.trackHeight / 2) + ) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + enabled = !disabled + ) { + onCheckedChange(!checked) + }, + contentAlignment = Alignment.CenterStart + ) { + Box( + modifier = Modifier + .offset(x = thumbOffset) + .size(shape.thumbSize) + .clip(RoundedCornerShape(shape.thumbSize / 2)) + .background(colors.thumbColor) + .border( + width = 1.dp, + color = colors.thumbBorderColor, + shape = RoundedCornerShape(shape.thumbSize / 2) + ) + ) + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/state/SwitchState.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/state/SwitchState.kt new file mode 100644 index 000000000..659acc8e4 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/state/SwitchState.kt @@ -0,0 +1,7 @@ +package com.atls.hyperion.ui.components.switch.state + +enum class SwitchState { + Default, + Checked, + Disabled +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/stories/Component.kt new file mode 100644 index 000000000..5015f5c81 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/stories/Component.kt @@ -0,0 +1,69 @@ +package com.atls.hyperion.ui.components.switch.stories + +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.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.storybook.shared.ui.ComponentVariants +import com.atls.hyperion.ui.components.switch.Switch +import com.atls.hyperion.ui.components.switch.styles.appearance.SwitchAppearance +import com.atls.hyperion.ui.components.switch.styles.appearance.default +import com.atls.hyperion.ui.components.switch.styles.shape.SwitchShape +import com.atls.hyperion.ui.components.switch.styles.shape.medium +import com.atls.hyperion.ui.primitives.HorizontalSpacer +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.tokens.layout.Weight + +class SwitchStory : ComponentExample { + override val name: String = "Switch" + + @Composable + override fun Content() { + var checked by remember { mutableStateOf(false) } + var enabled by remember { mutableStateOf(true) } + + Column { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = Space.g12), + verticalAlignment = Alignment.CenterVertically + ) { + Text(modifier = Modifier.weight(Weight.full), text = "Enabled") + HorizontalSpacer(Space.g12) + androidx.compose.material.Switch( + checked = enabled, + onCheckedChange = { enabled = it } + ) + } + VerticalSpacer(Space.g8) + ComponentVariants( + name = "Switch", + appearances = listOf( + "Primary" to { SwitchAppearance.default() } + ), + shapes = listOf( + "Medium" to { SwitchShape.medium() } + ) + ) { appearance: SwitchAppearance, shape: SwitchShape -> + Switch( + checked = checked, + disabled = !enabled, + appearance = appearance, + shape = shape, + onCheckedChange = { checked = it } + ) + } + } + } +} From 44202f0c496f4296b9076353798bf0371664e908 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 00:51:34 +0300 Subject: [PATCH 44/75] feat(ui): column layouts --- .../ui/primitives/layout/column/Lazy.kt | 39 +++++++++++++++++++ .../ui/primitives/layout/column/Static.kt | 23 +++++++++++ 2 files changed, 62 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Lazy.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Static.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Lazy.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Lazy.kt new file mode 100644 index 000000000..e5ac8dd0c --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Lazy.kt @@ -0,0 +1,39 @@ +package com.atls.hyperion.ui.primitives.layout.column + +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.ScrollableDefaults +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.theme.tokens.layout.Space +import androidx.compose.foundation.lazy.LazyColumn as ComposeColumn + +@Composable +fun LazyColumn( + modifier: Modifier = Modifier, + state: LazyListState = rememberLazyListState(), + contentPadding: PaddingValues = PaddingValues(Space.zero), + reverseLayout: Boolean = false, + verticalArrangement: Arrangement.Vertical = Arrangement.Top, + horizontalAlignment: Alignment.Horizontal = Alignment.Start, + flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), + userScrollEnabled: Boolean = true, + content: LazyListScope.() -> Unit +) { + ComposeColumn( + modifier = modifier, + state = state, + contentPadding = contentPadding, + reverseLayout = reverseLayout, + verticalArrangement = verticalArrangement, + horizontalAlignment = horizontalAlignment, + flingBehavior = flingBehavior, + userScrollEnabled = userScrollEnabled, + content = content + ) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Static.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Static.kt new file mode 100644 index 000000000..8a76a92d6 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/column/Static.kt @@ -0,0 +1,23 @@ +package com.atls.hyperion.ui.primitives.layout.column + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.foundation.layout.Column as ComposeColumn + +@Composable +fun Column( + modifier: Modifier = Modifier, + verticalArrangement: Arrangement.Vertical = Arrangement.Top, + horizontalAlignment: Alignment.Horizontal = Alignment.Start, + content: @Composable ColumnScope.() -> Unit +) { + ComposeColumn( + modifier = modifier, + verticalArrangement = verticalArrangement, + horizontalAlignment = horizontalAlignment, + content = content + ) +} From c4b5734eb0bd164e10c39d60f03c44d69349d89b Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 00:51:53 +0300 Subject: [PATCH 45/75] feat(ui): grid layout --- .../ui/primitives/layout/grid/Lazy.kt | 42 +++++++++++ .../ui/primitives/layout/grid/Orientation.kt | 6 ++ .../ui/primitives/layout/grid/Static.kt | 70 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Lazy.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Orientation.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Static.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Lazy.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Lazy.kt new file mode 100644 index 000000000..aa828d3b0 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Lazy.kt @@ -0,0 +1,42 @@ +package com.atls.hyperion.ui.primitives.layout.grid + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridScope +import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp + +@Composable +fun LazyGrid( + columns: Int, + orientation: GridOrientation, + modifier: Modifier = Modifier, + horizontalSpacing: Dp, + verticalSpacing: Dp, + content: LazyGridScope.() -> Unit +) { + when (orientation) { + GridOrientation.Vertical -> { + LazyVerticalGrid( + columns = GridCells.Fixed(columns), + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(horizontalSpacing), + verticalArrangement = Arrangement.spacedBy(verticalSpacing), + content = content + ) + } + + GridOrientation.Horizontal -> { + LazyHorizontalGrid( + rows = GridCells.Fixed(columns), + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(horizontalSpacing), + verticalArrangement = Arrangement.spacedBy(verticalSpacing), + content = content + ) + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Orientation.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Orientation.kt new file mode 100644 index 000000000..78e05afb1 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Orientation.kt @@ -0,0 +1,6 @@ +package com.atls.hyperion.ui.primitives.layout.grid + +enum class GridOrientation { + Vertical, + Horizontal +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Static.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Static.kt new file mode 100644 index 000000000..4d2558604 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/grid/Static.kt @@ -0,0 +1,70 @@ +package com.atls.hyperion.ui.primitives.layout.grid + +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.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.theme.tokens.layout.Weight + +@Composable +fun Grid( + items: List<@Composable () -> Unit>, + columns: Int, + orientation: GridOrientation, + modifier: Modifier = Modifier, + horizontalSpacing: Dp, + verticalSpacing: Dp +) { + when (orientation) { + GridOrientation.Vertical -> { + Column(modifier = modifier) { + items.chunked(columns).forEach { rowItems -> + Row( + horizontalArrangement = Arrangement.spacedBy(horizontalSpacing), + modifier = Modifier.fillMaxWidth() + ) { + rowItems.forEach { item -> + Box(modifier = Modifier.weight(Weight.full)) { + item() + } + } + + if (rowItems.size < columns) { + repeat(columns - rowItems.size) { + Spacer(modifier = Modifier.weight(Weight.full)) + } + } + } + VerticalSpacer(verticalSpacing) + } + } + } + + GridOrientation.Horizontal -> { + Row(modifier = modifier) { + items.chunked(columns).forEach { columnItems -> + Column( + verticalArrangement = Arrangement.spacedBy(verticalSpacing), + modifier = Modifier.weight(Weight.full) + ) { + columnItems.forEach { item -> + item() + } + + if (columnItems.size < columns) { + repeat(columns - columnItems.size) { + Spacer(modifier = Modifier.weight(Weight.full)) + } + } + } + } + } + } + } +} From 43b1966e9e37777f6c4d9d9d4110008df7b06ede Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 00:52:04 +0300 Subject: [PATCH 46/75] feat(ui): row layout --- .../hyperion/ui/primitives/layout/row/Lazy.kt | 39 +++++++++++++++++++ .../ui/primitives/layout/row/Static.kt | 23 +++++++++++ 2 files changed, 62 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Lazy.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Static.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Lazy.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Lazy.kt new file mode 100644 index 000000000..dea948061 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Lazy.kt @@ -0,0 +1,39 @@ +package com.atls.hyperion.ui.primitives.layout.row + +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.ScrollableDefaults +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.theme.tokens.layout.Space +import androidx.compose.foundation.lazy.LazyRow as ComposeRow + +@Composable +fun LazyRow( + modifier: Modifier = Modifier, + state: LazyListState = rememberLazyListState(), + contentPadding: PaddingValues = PaddingValues(Space.zero), + reverseLayout: Boolean = false, + horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, + verticalAlignment: Alignment.Vertical = Alignment.Top, + flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), + userScrollEnabled: Boolean = true, + content: LazyListScope.() -> Unit +) { + ComposeRow( + modifier = modifier, + state = state, + contentPadding = contentPadding, + reverseLayout = reverseLayout, + horizontalArrangement = horizontalArrangement, + verticalAlignment = verticalAlignment, + flingBehavior = flingBehavior, + userScrollEnabled = userScrollEnabled, + content = content + ) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Static.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Static.kt new file mode 100644 index 000000000..a7cf0542c --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/layout/row/Static.kt @@ -0,0 +1,23 @@ +package com.atls.hyperion.ui.primitives.layout.row + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.RowScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.foundation.layout.Row as ComposeRow + +@Composable +fun Row( + modifier: Modifier = Modifier, + horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, + verticalAlignment: Alignment.Vertical = Alignment.Top, + content: @Composable RowScope.() -> Unit +) { + ComposeRow( + modifier = modifier, + horizontalArrangement = horizontalArrangement, + verticalAlignment = verticalAlignment, + content = content + ) +} From e2a437e979bcffcfe0b272cdf1d959e85aea9992 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:00:45 +0300 Subject: [PATCH 47/75] feat(ui): date picker week days --- .../ui/fragment/datepicker/ui/WeekDays.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt new file mode 100644 index 000000000..04eb2f456 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt @@ -0,0 +1,39 @@ +package com.atls.hyperion.ui.fragment.datepicker.ui + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import com.atls.hyperion.ui.fragment.datepicker.config.DAYS_IN_WEEK +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatepickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatepickerShape +import com.atls.hyperion.ui.primitives.Text +import com.atls.hyperion.ui.theme.tokens.layout.Weight +import kotlinx.datetime.DayOfWeek +import kotlinx.datetime.format.DayOfWeekNames + +@Composable +fun WeekDays( + weekDays: List, + appearance: DatepickerAppearance, + shape: DatepickerShape, + dayNames: List = DayOfWeekNames.ENGLISH_ABBREVIATED.names +) { + require(dayNames.size == DAYS_IN_WEEK) { "dayNames must contain exactly 7 elements (Mon → Sun)" } + + Row(modifier = Modifier.fillMaxWidth()) { + weekDays.forEach { dayOfWeek -> + val nameIndex = (dayOfWeek.ordinal - weekDays.first().ordinal + DAYS_IN_WEEK) % DAYS_IN_WEEK + val shortName = dayNames[nameIndex] + + Text( + modifier = Modifier.weight(Weight.full), + textAlign = TextAlign.Center, + text = shortName, + typography = shape.dayHeaderTypography, + color = appearance.colors.weekDaysTextColor, + ) + } + } +} From f0c73fd4bb6fcaf04236e04cb4b3506f30741f78 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:09:07 +0300 Subject: [PATCH 48/75] feat(ui): calendar header component --- .../fragment/datepicker/ui/CalendarHeader.kt | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt new file mode 100644 index 000000000..c04b96ddf --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt @@ -0,0 +1,77 @@ +package com.atls.hyperion.ui.fragment.datepicker.ui + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import com.atls.hyperion.ui.components.divider.horizontal.HorizontalDivider +import com.atls.hyperion.ui.fragment.datepicker.model.CalendarDivider +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatepickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatepickerShape +import com.atls.hyperion.ui.generated.resources.Res +import com.atls.hyperion.ui.generated.resources.chevron_left +import com.atls.hyperion.ui.generated.resources.chevron_right +import com.atls.hyperion.ui.primitives.Icon +import org.jetbrains.compose.resources.painterResource + + +@Composable +fun CalendarHeader( + monthName: String, + appearance: DatepickerAppearance, + shape: DatepickerShape, + beforeIcon: Painter = painterResource(Res.drawable.chevron_left), + afterIcon: Painter = painterResource(Res.drawable.chevron_right), + arrangement: Arrangement.Horizontal = Arrangement.SpaceBetween, + alignment: Alignment.Vertical = Alignment.CenterVertically, + onPrevMonth: () -> Unit, + onNextMonth: () -> Unit, +) { + if (shape.divider == CalendarDivider.TOP) { + HorizontalDivider( + appearance = appearance.dividerAppearance, + shape = shape.dividerShape + ) + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(shape.headerHorizontalPadding), + horizontalArrangement = arrangement, + verticalAlignment = alignment + ) { + Icon( + icon = beforeIcon, + size = shape.headerIconSize, + modifier = Modifier.clickable { onPrevMonth() }, + color = appearance.colors.arrowColor + ) + + Text( + text = monthName, + style = shape.headerTypography, + color = appearance.colors.headerTextColor + ) + + Icon( + icon = afterIcon, + size = shape.headerIconSize, + modifier = Modifier.clickable { onNextMonth() }, + color = appearance.colors.arrowColor + ) + } + + if (shape.divider == CalendarDivider.BOTTOM) { + HorizontalDivider( + appearance = appearance.dividerAppearance, + shape = shape.dividerShape + ) + } +} From 0bdfe49ebae0c103d5241a27dae368fbd4f9760a Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:18:58 +0300 Subject: [PATCH 49/75] feat(ui): date picker day component --- .../hyperion/ui/fragment/datepicker/ui/Day.kt | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt new file mode 100644 index 000000000..c83a8afa0 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt @@ -0,0 +1,93 @@ +package com.atls.hyperion.ui.fragment.datepicker.ui + +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.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatepickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatepickerShape +import com.atls.hyperion.ui.primitives.Text +import com.atls.hyperion.ui.shared.layout.aspectSquare +import com.atls.hyperion.ui.theme.tokens.colors.Colors +import com.kizitonwose.calendar.core.CalendarDay +import com.kizitonwose.calendar.core.DayPosition +import kotlinx.datetime.LocalDate + +@Composable +fun Day( + day: CalendarDay, + isSelected: Boolean, + isInRange: Boolean, + isRangeStart: Boolean, + isRangeEnd: Boolean, + appearance: DatepickerAppearance, + shape: DatepickerShape, + onClick: (LocalDate) -> Unit, +) { + val isCurrentMonth = day.position == DayPosition.MonthDate + if (!isCurrentMonth) { + Box(modifier = Modifier.aspectSquare()) + return + } + + val date = LocalDate(day.date.year, day.date.monthNumber, day.date.dayOfMonth) + + val backgroundColor = when { + isSelected || isRangeStart || isRangeEnd -> appearance.cellActiveBackgroundColor + isInRange -> appearance.cellInRangeBackgroundColor + else -> appearance.cellBackgroundColor + } + + val textColor = when { + isSelected || isRangeStart || isRangeEnd -> appearance.cellActiveTextColor + isInRange -> appearance.cellInRangeTextColor + else -> appearance.cellTextColor + } + + val containerModifier = Modifier + .aspectSquare() + .padding(shape.cellSpacing) + .clip(shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius)) + .background(backgroundColor) + .padding(shape.cellPadding) + .then( + if ((isSelected || isRangeStart || isRangeEnd) && appearance.cellActiveBorderColor != Colors.Palette.transparent) + Modifier.border( + shape.cellBorderWidth, + appearance.cellActiveBorderColor, + shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius) + ) + else if (isInRange && appearance.cellInRangeBorderColor != Colors.Palette.transparent) + Modifier.border( + shape.cellBorderWidth, + appearance.cellInRangeBorderColor, + shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius) + ) + else if (appearance.cellBorderColor != Colors.Palette.transparent) + Modifier.border( + shape.cellBorderWidth, + appearance.cellBorderColor, + shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius) + ) + else Modifier + ) + .clickable { onClick(date) } + + + Box( + modifier = containerModifier, + contentAlignment = Alignment.Center + ) { + Text( + text = day.date.dayOfMonth.toString(), + color = textColor, + typography = shape.cellTypography + ) + } +} From 202bf44a229356ee1898e268ae193fc6feaa3d97 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:51:48 +0300 Subject: [PATCH 50/75] chore(theme): aspect square util --- .../com/atls/hyperion/ui/shared/layout/AspectSquare.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/layout/AspectSquare.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/layout/AspectSquare.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/layout/AspectSquare.kt new file mode 100644 index 000000000..50377e1f5 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/shared/layout/AspectSquare.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.shared.layout + +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +fun Modifier.aspectSquare(): Modifier = + this.aspectRatio(1f) From 9987ce9bef3c56876691d2ce87781c0b6ed1185e Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:52:12 +0300 Subject: [PATCH 51/75] chore(theme): icon sizes --- .../atls/hyperion/ui/theme/tokens/components/IconSize.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/IconSize.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/IconSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/IconSize.kt new file mode 100644 index 000000000..33bd8f36b --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/IconSize.kt @@ -0,0 +1,7 @@ +package com.atls.hyperion.ui.theme.tokens.components + +import androidx.compose.ui.unit.dp + +object IconSize { + val medium = 24.dp +} From 7e9c5ceb65f975dd021ded9338df27c3fd72973b Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:52:37 +0300 Subject: [PATCH 52/75] feat(ui): date picker components --- .../fragment/datepicker/ui/CalendarHeader.kt | 24 +-- .../datepicker/ui/DatePickerContent.kt | 149 ++++++++++++++++++ .../hyperion/ui/fragment/datepicker/ui/Day.kt | 24 +-- .../ui/fragment/datepicker/ui/WeekDays.kt | 10 +- 4 files changed, 182 insertions(+), 25 deletions(-) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt index c04b96ddf..62d878968 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt @@ -5,27 +5,27 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import com.atls.hyperion.ui.components.divider.horizontal.HorizontalDivider import com.atls.hyperion.ui.fragment.datepicker.model.CalendarDivider -import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatepickerAppearance -import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatepickerShape +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape import com.atls.hyperion.ui.generated.resources.Res import com.atls.hyperion.ui.generated.resources.chevron_left import com.atls.hyperion.ui.generated.resources.chevron_right import com.atls.hyperion.ui.primitives.Icon +import com.atls.hyperion.ui.primitives.Text +import com.atls.hyperion.ui.primitives.VerticalSpacer import org.jetbrains.compose.resources.painterResource - @Composable fun CalendarHeader( monthName: String, - appearance: DatepickerAppearance, - shape: DatepickerShape, + appearance: DatePickerAppearance, + shape: DatePickerShape, beforeIcon: Painter = painterResource(Res.drawable.chevron_left), afterIcon: Painter = painterResource(Res.drawable.chevron_right), arrangement: Arrangement.Horizontal = Arrangement.SpaceBetween, @@ -38,12 +38,13 @@ fun CalendarHeader( appearance = appearance.dividerAppearance, shape = shape.dividerShape ) + VerticalSpacer(shape.headerSpacing) } Row( modifier = Modifier .fillMaxWidth() - .padding(shape.headerHorizontalPadding), + .padding(horizontal = shape.headerHorizontalPadding), horizontalArrangement = arrangement, verticalAlignment = alignment ) { @@ -51,24 +52,25 @@ fun CalendarHeader( icon = beforeIcon, size = shape.headerIconSize, modifier = Modifier.clickable { onPrevMonth() }, - color = appearance.colors.arrowColor + color = appearance.arrowColor ) Text( text = monthName, - style = shape.headerTypography, - color = appearance.colors.headerTextColor + typography = shape.headerTypography, + color = appearance.headerTextColor ) Icon( icon = afterIcon, size = shape.headerIconSize, modifier = Modifier.clickable { onNextMonth() }, - color = appearance.colors.arrowColor + color = appearance.arrowColor ) } if (shape.divider == CalendarDivider.BOTTOM) { + VerticalSpacer(shape.headerSpacing) HorizontalDivider( appearance = appearance.dividerAppearance, shape = shape.dividerShape diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt new file mode 100644 index 000000000..104b54bfa --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt @@ -0,0 +1,149 @@ +package com.atls.hyperion.ui.fragment.datepicker.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.fragment.datepicker.config.DAYS_IN_WEEK +import com.atls.hyperion.ui.fragment.datepicker.config.WEEK_RANGE +import com.atls.hyperion.ui.fragment.datepicker.lib.next +import com.atls.hyperion.ui.fragment.datepicker.lib.previous +import com.atls.hyperion.ui.fragment.datepicker.model.DateSelection +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape +import com.atls.hyperion.ui.primitives.layout.column.Column +import com.kizitonwose.calendar.compose.HorizontalCalendar +import com.kizitonwose.calendar.compose.rememberCalendarState +import com.kizitonwose.calendar.core.firstDayOfWeekFromLocale +import kotlinx.coroutines.launch +import kotlinx.datetime.DayOfWeek +import kotlinx.datetime.TimeZone +import kotlinx.datetime.YearMonth +import kotlinx.datetime.toLocalDateTime +import kotlin.time.Clock +import kotlin.time.ExperimentalTime + +@OptIn(ExperimentalTime::class) +@Composable +fun DatePickerContent( + modifier: Modifier = Modifier, + selection: DateSelection, + onSelectionChange: (DateSelection) -> Unit, + appearance: DatePickerAppearance, + shape: DatePickerShape, +) { + val today = remember { + Clock.System.now() + .toLocalDateTime(TimeZone.currentSystemDefault()) + .date + } + + val currentMonth = remember { YearMonth(today.year, today.month) } + val startMonth = remember { YearMonth(1, today.month) } + val endMonth = remember { YearMonth(2200, today.month) } + val firstDayOfWeek = remember { firstDayOfWeekFromLocale() } + + val state = rememberCalendarState( + startMonth = startMonth, + endMonth = endMonth, + firstVisibleMonth = currentMonth, + firstDayOfWeek = firstDayOfWeek + ) + + val coroutineScope = rememberCoroutineScope() + + Column(modifier = modifier.background(appearance.backgroundColor)) { + + val visibleMonth = state.firstVisibleMonth.yearMonth + val monthName = + visibleMonth.month.name.lowercase().replaceFirstChar { it.uppercase() } + + CalendarHeader( + monthName = "$monthName ${visibleMonth.year}", + appearance = appearance, + shape = shape, + onPrevMonth = { + coroutineScope.launch { + state.animateScrollToMonth(visibleMonth.previous()) + } + }, + onNextMonth = { + coroutineScope.launch { + state.animateScrollToMonth(visibleMonth.next()) + } + } + ) + + HorizontalCalendar( + modifier = Modifier + .fillMaxWidth() + .padding(shape.calendarPadding), + + state = state, + dayContent = { day -> + val date = day.date + + val isSelected = when (selection) { + is DateSelection.Single -> selection.date == date + is DateSelection.Range -> false + } + + val isRangeStart = when (selection) { + is DateSelection.Range -> selection.start == date + else -> false + } + + val isRangeEnd = when (selection) { + is DateSelection.Range -> selection.end == date + else -> false + } + + val isInRange = when (selection) { + is DateSelection.Range -> + selection.start != null && + selection.end != null && + date > selection.start && + date < selection.end + + else -> false + } + + Day( + day = day, + isSelected = isSelected, + isInRange = isInRange, + isRangeStart = isRangeStart, + isRangeEnd = isRangeEnd, + appearance = appearance, + shape = shape, + onClick = { clicked -> + onSelectionChange( + when (selection) { + is DateSelection.Single -> + selection.copy(date = clicked) + + is DateSelection.Range -> + selection.next(clicked) + } + ) + } + ) + }, + + monthHeader = { + WeekDays( + weekDays = state.firstDayOfWeek.let { first -> + WEEK_RANGE.map { + DayOfWeek.entries[(first.ordinal + it) % DAYS_IN_WEEK] + } + }, + appearance = appearance, + shape = shape + ) + } + ) + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt index c83a8afa0..4c9b836cd 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt @@ -5,13 +5,12 @@ import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatepickerAppearance -import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatepickerShape +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape import com.atls.hyperion.ui.primitives.Text import com.atls.hyperion.ui.shared.layout.aspectSquare import com.atls.hyperion.ui.theme.tokens.colors.Colors @@ -26,8 +25,8 @@ fun Day( isInRange: Boolean, isRangeStart: Boolean, isRangeEnd: Boolean, - appearance: DatepickerAppearance, - shape: DatepickerShape, + appearance: DatePickerAppearance, + shape: DatePickerShape, onClick: (LocalDate) -> Unit, ) { val isCurrentMonth = day.position == DayPosition.MonthDate @@ -44,16 +43,23 @@ fun Day( else -> appearance.cellBackgroundColor } + val cellShape = when { + isSelected -> shape.cellActiveShape + isInRange -> shape.cellRangeShape + else -> shape.cellShape + } + val textColor = when { isSelected || isRangeStart || isRangeEnd -> appearance.cellActiveTextColor isInRange -> appearance.cellInRangeTextColor else -> appearance.cellTextColor } + val containerModifier = Modifier .aspectSquare() .padding(shape.cellSpacing) - .clip(shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius)) + .clip(cellShape) .background(backgroundColor) .padding(shape.cellPadding) .then( @@ -61,19 +67,19 @@ fun Day( Modifier.border( shape.cellBorderWidth, appearance.cellActiveBorderColor, - shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius) + cellShape ) else if (isInRange && appearance.cellInRangeBorderColor != Colors.Palette.transparent) Modifier.border( shape.cellBorderWidth, appearance.cellInRangeBorderColor, - shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius) + cellShape ) else if (appearance.cellBorderColor != Colors.Palette.transparent) Modifier.border( shape.cellBorderWidth, appearance.cellBorderColor, - shape.cellShape ?: RoundedCornerShape(shape.cellCornerRadius) + cellShape ) else Modifier ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt index 04eb2f456..dcf60fd70 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt @@ -6,8 +6,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import com.atls.hyperion.ui.fragment.datepicker.config.DAYS_IN_WEEK -import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatepickerAppearance -import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatepickerShape +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape import com.atls.hyperion.ui.primitives.Text import com.atls.hyperion.ui.theme.tokens.layout.Weight import kotlinx.datetime.DayOfWeek @@ -16,8 +16,8 @@ import kotlinx.datetime.format.DayOfWeekNames @Composable fun WeekDays( weekDays: List, - appearance: DatepickerAppearance, - shape: DatepickerShape, + appearance: DatePickerAppearance, + shape: DatePickerShape, dayNames: List = DayOfWeekNames.ENGLISH_ABBREVIATED.names ) { require(dayNames.size == DAYS_IN_WEEK) { "dayNames must contain exactly 7 elements (Mon → Sun)" } @@ -32,7 +32,7 @@ fun WeekDays( textAlign = TextAlign.Center, text = shortName, typography = shape.dayHeaderTypography, - color = appearance.colors.weekDaysTextColor, + color = appearance.weekDaysTextColor, ) } } From 12d5782feb1a80be5731f9e2b0e973f9e0a18f71 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:52:54 +0300 Subject: [PATCH 53/75] feat(ui): date picker fragment --- .../ui/fragment/datepicker/Fragment.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt new file mode 100644 index 000000000..6d08c55c4 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt @@ -0,0 +1,33 @@ +package com.atls.hyperion.ui.fragment.datepicker + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.modal.popup.Popup +import com.atls.hyperion.ui.fragment.datepicker.model.DateSelection +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.default +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape +import com.atls.hyperion.ui.fragment.datepicker.style.shape.default +import com.atls.hyperion.ui.fragment.datepicker.ui.DatePickerContent + +@Composable +fun DatePicker( + modifier: Modifier = Modifier, + selection: DateSelection, + onSelectionChange: (DateSelection) -> Unit, + onDismiss: () -> Unit, + appearance: DatePickerAppearance = DatePickerAppearance.default(), + shape: DatePickerShape = DatePickerShape.default() +) { + Popup( + modifier = modifier, + onDismissRequest = onDismiss + ) { + DatePickerContent( + selection = selection, + onSelectionChange = onSelectionChange, + appearance = appearance, + shape = shape + ) + } +} From be5606901f89ea1d113271cf48d64d3dca2ba542 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:53:47 +0300 Subject: [PATCH 54/75] feat(ui): date picker model --- .../ui/fragment/datepicker/model/DateSelection.kt | 15 +++++++++++++++ .../fragment/datepicker/model/DividerPosition.kt | 5 +++++ 2 files changed, 20 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DateSelection.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DividerPosition.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DateSelection.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DateSelection.kt new file mode 100644 index 000000000..2996cd71c --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DateSelection.kt @@ -0,0 +1,15 @@ +package com.atls.hyperion.ui.fragment.datepicker.model + +import kotlinx.datetime.LocalDate + +sealed interface DateSelection { + + data class Single( + val date: LocalDate? = null + ) : DateSelection + + data class Range( + val start: LocalDate? = null, + val end: LocalDate? = null + ) : DateSelection +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DividerPosition.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DividerPosition.kt new file mode 100644 index 000000000..a6340af9e --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/model/DividerPosition.kt @@ -0,0 +1,5 @@ +package com.atls.hyperion.ui.fragment.datepicker.model + +enum class DividerPosition { + TOP, BOTTOM, NONE +} From 27c19d8fd5c78aba4f0f216bf9036946ff42b7e8 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:53:59 +0300 Subject: [PATCH 55/75] feat(ui): date utils --- .../ui/fragment/datepicker/lib/NextDateRange.kt | 16 ++++++++++++++++ .../ui/fragment/datepicker/lib/NextMonth.kt | 10 ++++++++++ .../ui/fragment/datepicker/lib/PreviousMonth.kt | 10 ++++++++++ 3 files changed, 36 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextDateRange.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextMonth.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/PreviousMonth.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextDateRange.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextDateRange.kt new file mode 100644 index 000000000..cb65aa690 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextDateRange.kt @@ -0,0 +1,16 @@ +package com.atls.hyperion.ui.fragment.datepicker.lib + +import com.atls.hyperion.ui.fragment.datepicker.model.DateSelection +import kotlinx.datetime.LocalDate + +fun DateSelection.Range.next(clicked: LocalDate): DateSelection.Range = + when { + start == null || end != null -> + copy(start = clicked, end = null) + + clicked < start -> + copy(start = clicked, end = start) + + else -> + copy(end = clicked) + } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextMonth.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextMonth.kt new file mode 100644 index 000000000..7d054307f --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/NextMonth.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.fragment.datepicker.lib + +import kotlinx.datetime.Month +import kotlinx.datetime.YearMonth + +fun YearMonth.next(): YearMonth = + if (month == Month.DECEMBER) + YearMonth(year + 1, Month.JANUARY) + else + YearMonth(year, Month.entries[month.ordinal + 1]) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/PreviousMonth.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/PreviousMonth.kt new file mode 100644 index 000000000..1610c86fb --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/lib/PreviousMonth.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.fragment.datepicker.lib + +import kotlinx.datetime.Month +import kotlinx.datetime.YearMonth + +fun YearMonth.previous(): YearMonth = + if (month == Month.JANUARY) + YearMonth(year - 1, Month.DECEMBER) + else + YearMonth(year, Month.entries[month.ordinal - 1]) From 22f485a8c984f6949b693df1c9fd67b083f9f3fc Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:54:15 +0300 Subject: [PATCH 56/75] chore(ui): date picker constants --- .../atls/hyperion/ui/fragment/datepicker/config/Constants.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/config/Constants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/config/Constants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/config/Constants.kt new file mode 100644 index 000000000..e86eadb6f --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/config/Constants.kt @@ -0,0 +1,4 @@ +package com.atls.hyperion.ui.fragment.datepicker.config + +internal val DAYS_IN_WEEK = 7 +internal val WEEK_RANGE = 0..6 From b49d5424ec5525cb9d308166247598619a792366 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:54:32 +0300 Subject: [PATCH 57/75] feat(ui): date picker styles --- .../datepicker/style/appearance/Appearance.kt | 27 ++++++++++++ .../datepicker/style/appearance/Variants.kt | 27 ++++++++++++ .../fragment/datepicker/style/shape/Shape.kt | 34 +++++++++++++++ .../datepicker/style/shape/Variants.kt | 43 +++++++++++++++++++ .../fragment/datepicker/ui/CalendarHeader.kt | 6 +-- 5 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt new file mode 100644 index 000000000..cb1567a4a --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt @@ -0,0 +1,27 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance + +import androidx.compose.ui.graphics.Color +import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance +import com.atls.hyperion.ui.components.modal.style.appearance.ModalAppearance + +data class DatePickerAppearance( + val cellBackgroundColor: Color, + val cellTextColor: Color, + val cellActiveBackgroundColor: Color, + val cellActiveTextColor: Color, + val cellInRangeBackgroundColor: Color, + val cellInRangeTextColor: Color, + val cellBorderColor: Color = Color.Transparent, + val cellActiveBorderColor: Color = Color.Transparent, + val cellInRangeBorderColor: Color = Color.Transparent, + val cellHeaderTextColor: Color, + val backgroundColor: Color, + val headerTextColor: Color, + val weekDaysTextColor: Color = headerTextColor, + val arrowColor: Color, + val dividerColor: Color, + val dividerAppearance: DividerAppearance, + val modalAppearance: ModalAppearance +) { + companion object Companion +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Variants.kt new file mode 100644 index 000000000..e59fdb1fa --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Variants.kt @@ -0,0 +1,27 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance +import com.atls.hyperion.ui.components.divider.style.appearance.default +import com.atls.hyperion.ui.components.modal.style.appearance.ModalAppearance +import com.atls.hyperion.ui.components.modal.style.appearance.default +import com.atls.hyperion.ui.theme.tokens.colors.Colors as TokenColors + +@Composable +fun DatePickerAppearance.Companion.default(): DatePickerAppearance = + DatePickerAppearance( + cellBackgroundColor = TokenColors.Palette.transparent, + cellTextColor = TokenColors.Text.black, + cellActiveBackgroundColor = TokenColors.Palette.blue, + cellActiveTextColor = TokenColors.Text.white, + cellInRangeBackgroundColor = TokenColors.Palette.lightPurple, + cellInRangeTextColor = TokenColors.Text.black, + cellHeaderTextColor = TokenColors.Text.gray, + backgroundColor = TokenColors.Palette.white, + headerTextColor = TokenColors.Text.black, + arrowColor = TokenColors.Text.black, + dividerColor = TokenColors.Palette.gray, + weekDaysTextColor = TokenColors.Text.black, + dividerAppearance = DividerAppearance.default(), + modalAppearance = ModalAppearance.default() + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt new file mode 100644 index 000000000..17d915078 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt @@ -0,0 +1,34 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.components.divider.style.shape.DividerShape +import com.atls.hyperion.ui.components.modal.style.shape.ModalShape +import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke + +data class DatePickerShape( + val cellSpacing: Dp, + val cellPadding: Dp, + val cellBorderWidth: Dp = BorderStroke.none, + val cellBorderColor: Color = Color.Transparent, + val cellShape: Shape, + val cellActiveShape: Shape = cellShape, + val cellRangeShape: Shape = RectangleShape, + val cellTypography: TextStyle, + val headerTypography: TextStyle, + val headerSpacing: Dp, + val calendarPadding: PaddingValues, + val dayHeaderTypography: TextStyle, + val headerIconSize: Dp, + val headerHorizontalPadding: Dp, + val divider: DividerPosition = DividerPosition.NONE, + val dividerShape: DividerShape, + val modalShape: ModalShape +) { + companion object Companion +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt new file mode 100644 index 000000000..9ad908e0f --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt @@ -0,0 +1,43 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import com.atls.hyperion.ui.components.divider.style.shape.DividerShape +import com.atls.hyperion.ui.components.divider.style.shape.default +import com.atls.hyperion.ui.components.modal.style.shape.ModalShape +import com.atls.hyperion.ui.components.modal.style.shape.popup +import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition +import com.atls.hyperion.ui.theme.tokens.components.IconSize +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.typography.FontSize +import com.atls.hyperion.ui.theme.typography.FontWeight + +@Composable +fun DatePickerShape.Companion.default(): DatePickerShape = + DatePickerShape( + cellTypography = TextStyle( + fontSize = FontSize.xs, + fontWeight = FontWeight.regular, + ), + headerTypography = TextStyle( + fontSize = FontSize.md, + fontWeight = FontWeight.bold, + ), + dayHeaderTypography = TextStyle( + fontSize = FontSize.xs2, + fontWeight = FontWeight.medium, + ), + cellSpacing = Space.zero, + cellPadding = Space.g8, + cellShape = RoundedCornerShape(CornerRadius.xs2), + calendarPadding = PaddingValues(Space.g12), + headerIconSize = IconSize.medium, + headerSpacing = Space.g12, + headerHorizontalPadding = Space.g12, + divider = DividerPosition.BOTTOM, + dividerShape = DividerShape.default(), + modalShape = ModalShape.popup() + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt index 62d878968..7fda72508 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import com.atls.hyperion.ui.components.divider.horizontal.HorizontalDivider -import com.atls.hyperion.ui.fragment.datepicker.model.CalendarDivider +import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape import com.atls.hyperion.ui.generated.resources.Res @@ -33,7 +33,7 @@ fun CalendarHeader( onPrevMonth: () -> Unit, onNextMonth: () -> Unit, ) { - if (shape.divider == CalendarDivider.TOP) { + if (shape.divider == DividerPosition.TOP) { HorizontalDivider( appearance = appearance.dividerAppearance, shape = shape.dividerShape @@ -69,7 +69,7 @@ fun CalendarHeader( ) } - if (shape.divider == CalendarDivider.BOTTOM) { + if (shape.divider == DividerPosition.BOTTOM) { VerticalSpacer(shape.headerSpacing) HorizontalDivider( appearance = appearance.dividerAppearance, From 6b25b13cd684dacddddad2ea1209276ad78d24cd Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:54:56 +0300 Subject: [PATCH 58/75] feat(ui): chevron icons --- .../composeResources/drawable/chevron_left.xml | 10 ++++++++++ .../composeResources/drawable/chevron_right.xml | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_left.xml create mode 100644 mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_right.xml diff --git a/mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_left.xml b/mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_left.xml new file mode 100644 index 000000000..62b41a877 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_left.xml @@ -0,0 +1,10 @@ + + + diff --git a/mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_right.xml b/mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_right.xml new file mode 100644 index 000000000..3979fa801 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/composeResources/drawable/chevron_right.xml @@ -0,0 +1,10 @@ + + + From 278ef5febd41e9dc6845326b41fa16e4654432a7 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:55:11 +0300 Subject: [PATCH 59/75] feat(theme): draghandle sizes --- .../ui/theme/tokens/components/DragHandleSize.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/DragHandleSize.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/DragHandleSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/DragHandleSize.kt new file mode 100644 index 000000000..c21fa6ed0 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/DragHandleSize.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.theme.tokens.components + +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +object DragHandleSize { + val height: Dp = 6.dp + val width: Dp = 79.dp +} From 210881adcb7a794a14fedd8f9f81339b94a1474c Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:55:21 +0300 Subject: [PATCH 60/75] chore(theme): new elevation token --- .../kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt index ff5674e06..871c26c28 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt @@ -4,4 +4,5 @@ import androidx.compose.ui.unit.dp object Elevation { val zero = 0.dp + val tiny = 2.dp } From e681594da0eea26eade8bc256a2b8f7e5141ddf8 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:55:54 +0300 Subject: [PATCH 61/75] refactor(ui): rename divider files --- .../divider/horizontal/{HorizontalDivider.kt => Component.kt} | 0 .../divider/vertical/{VerticalDivider.kt => Component.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/{HorizontalDivider.kt => Component.kt} (100%) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/{VerticalDivider.kt => Component.kt} (100%) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/HorizontalDivider.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/Component.kt similarity index 100% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/HorizontalDivider.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/horizontal/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/VerticalDivider.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/Component.kt similarity index 100% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/VerticalDivider.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/divider/vertical/Component.kt From 55eae6d27b09b20851993811ff6cfbfa676d139c Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:57:16 +0300 Subject: [PATCH 62/75] feat(ui): drag handle component --- .../modal/bottom/dragHandle/Component.kt | 29 +++++++++++++++++++ .../dragHandle/style/appearance/Appearance.kt | 9 ++++++ .../dragHandle/style/appearance/Variants.kt | 10 +++++++ .../bottom/dragHandle/style/shape/Shape.kt | 13 +++++++++ .../bottom/dragHandle/style/shape/Variants.kt | 16 ++++++++++ 5 files changed, 77 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/Component.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/Component.kt new file mode 100644 index 000000000..ecb695f41 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/Component.kt @@ -0,0 +1,29 @@ +package com.atls.hyperion.ui.components.modal.bottom.dragHandle + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.appearance.DragHandleAppearance +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.shape.DragHandleShape + +@Composable +fun DragHandle( + appearance: DragHandleAppearance, + shape: DragHandleShape +) { + Box( + modifier = Modifier + .padding(shape.paddings) + .width(shape.width) + .height(shape.height) + .background( + color = appearance.backgroundColor, + shape = RoundedCornerShape(shape.cornerRadius) + ) + ) +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Appearance.kt new file mode 100644 index 000000000..14cea132b --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Appearance.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.appearance + +import androidx.compose.ui.graphics.Color + +data class DragHandleAppearance( + val backgroundColor: Color +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Variants.kt new file mode 100644 index 000000000..b6b63ace1 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/appearance/Variants.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.appearance + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.colors.Colors + +@Composable +fun DragHandleAppearance.Companion.default(): DragHandleAppearance = + DragHandleAppearance( + backgroundColor = Colors.Palette.gray + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Shape.kt new file mode 100644 index 000000000..78edfd16a --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Shape.kt @@ -0,0 +1,13 @@ +package com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.unit.Dp + +data class DragHandleShape( + val height: Dp, + val width: Dp, + val cornerRadius: Dp, + val paddings: PaddingValues +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt new file mode 100644 index 000000000..8fc610a60 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt @@ -0,0 +1,16 @@ +package com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.components.DragHandleSize +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Space + +@Composable +fun DragHandleShape.Companion.default(): DragHandleShape = + DragHandleShape( + height = DragHandleSize.height, + width = DragHandleSize.width, + cornerRadius = CornerRadius.xl6, + paddings = PaddingValues(top = Space.g8) + ) From a04a68b30e57e4cffa63f1b2e4a1ad511ad641a4 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:57:31 +0300 Subject: [PATCH 63/75] feat(ui): modal styles --- .../modal/style/appearance/Appearance.kt | 9 +++++ .../modal/style/appearance/Variants.kt | 10 ++++++ .../ui/components/modal/style/shape/Shape.kt | 14 ++++++++ .../components/modal/style/shape/Variants.kt | 34 +++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Shape.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Appearance.kt new file mode 100644 index 000000000..45aa7714d --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Appearance.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.components.modal.style.appearance + +import androidx.compose.ui.graphics.Color + +data class ModalAppearance( + val backgroundColor: Color +) { + companion object Companion +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Variants.kt new file mode 100644 index 000000000..52bafdf81 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/appearance/Variants.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.components.modal.style.appearance + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.colors.Colors + +@Composable +fun ModalAppearance.Companion.default(): ModalAppearance = + ModalAppearance( + backgroundColor = Colors.Palette.white + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Shape.kt new file mode 100644 index 000000000..5245e4d98 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Shape.kt @@ -0,0 +1,14 @@ +package com.atls.hyperion.ui.components.modal.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.unit.Dp + +data class ModalShape( + val shape: Shape, + val shadowElevation: Dp, + val paddings: PaddingValues, + val spacers: PaddingValues +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt new file mode 100644 index 000000000..ea3f71b06 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt @@ -0,0 +1,34 @@ +package com.atls.hyperion.ui.components.modal.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.theme.tokens.Elevation +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Space + +@Composable +fun ModalShape.Companion.popup(): ModalShape = + ModalShape( + shape = RoundedCornerShape(CornerRadius.zero), + shadowElevation = Elevation.tiny, + paddings = PaddingValues(Space.g20), + spacers = PaddingValues(horizontal = Space.g24) + ) + +@Composable +fun ModalShape.Companion.bottom(): ModalShape = + ModalShape( + shape = RoundedCornerShape( + topStart = CornerRadius.xl4, + topEnd = CornerRadius.xl4, + ), + shadowElevation = Elevation.zero, + paddings = PaddingValues( + top = Space.g4, + bottom = Space.g20, + start = Space.g20, + end = Space.g20 + ), + spacers = PaddingValues(horizontal = Space.zero) + ) From f8133688319c27790eeffa8c9bbff47437f6e66d Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:58:11 +0300 Subject: [PATCH 64/75] feat(ui): modal components with stories --- .../ui/components/modal/bottom/Component.kt | 59 ++++++++++++++ .../modal/bottom/stories/Component.kt | 77 +++++++++++++++++++ .../ui/components/modal/popup/Popup.kt | 43 +++++++++++ .../modal/popup/stories/Component.kt | 63 +++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/Component.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/stories/Component.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/Popup.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/stories/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/Component.kt new file mode 100644 index 000000000..f691e5306 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/Component.kt @@ -0,0 +1,59 @@ +package com.atls.hyperion.ui.components.modal.bottom + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.SheetState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.DragHandle +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.appearance.DragHandleAppearance +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.appearance.default +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.shape.DragHandleShape +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.shape.default +import com.atls.hyperion.ui.components.modal.style.appearance.ModalAppearance +import com.atls.hyperion.ui.components.modal.style.appearance.default +import com.atls.hyperion.ui.components.modal.style.shape.ModalShape +import com.atls.hyperion.ui.components.modal.style.shape.bottom + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BottomDialog( + modifier: Modifier = Modifier, + appearance: ModalAppearance = ModalAppearance.default(), + shape: ModalShape = ModalShape.bottom(), + dragHandleShape: DragHandleShape = DragHandleShape.default(), + dragHandleAppearance: DragHandleAppearance = DragHandleAppearance.default(), + dragHandle: @Composable () -> Unit = { + DragHandle( + appearance = dragHandleAppearance, + shape = dragHandleShape + ) + }, + sheetState: SheetState, + onDismissRequest: () -> Unit, + content: @Composable () -> Unit +) { + ModalBottomSheet( + modifier = modifier + .windowInsetsPadding(WindowInsets.statusBars), + onDismissRequest = onDismissRequest, + sheetState = sheetState, + shape = shape.shape, + dragHandle = dragHandle, + containerColor = appearance.backgroundColor, + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(shape.paddings) + ) { + content() + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/stories/Component.kt new file mode 100644 index 000000000..8ce2156a5 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/stories/Component.kt @@ -0,0 +1,77 @@ +package com.atls.hyperion.ui.components.modal.bottom.stories + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.ui.components.button.Button +import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance +import com.atls.hyperion.ui.components.button.styles.appearance.blue +import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape +import com.atls.hyperion.ui.components.button.styles.shape.normal +import com.atls.hyperion.ui.components.modal.bottom.BottomDialog +import com.atls.hyperion.ui.theme.tokens.layout.Space +import kotlinx.coroutines.launch + +class BottomDialogStory : ComponentExample { + override val name: String = "BottomDialog" + + @OptIn(ExperimentalMaterial3Api::class) + @Composable + override fun Content() { + var showDialog by remember { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState() + val scope = rememberCoroutineScope() + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(Space.g12) + ) { + Button( + text = "Show Bottom Dialog", + appearance = ButtonAppearance.blue(), + shape = ButtonShape.normal(), + onClick = { showDialog = true } + ) + + if (showDialog) { + BottomDialog( + sheetState = sheetState, + onDismissRequest = { showDialog = false } + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(Space.g16) + ) { + Text(text = "This is a Bottom Dialog") + Button( + modifier = Modifier.padding(top = Space.g12), + text = "Close", + appearance = ButtonAppearance.blue(), + shape = ButtonShape.normal(), + onClick = { + scope.launch { sheetState.hide() }.invokeOnCompletion { + if (!sheetState.isVisible) { + showDialog = false + } + } + } + ) + } + } + } + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/Popup.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/Popup.kt new file mode 100644 index 000000000..f5f5cd0f8 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/Popup.kt @@ -0,0 +1,43 @@ +package com.atls.hyperion.ui.components.modal.popup + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.atls.hyperion.ui.components.modal.style.appearance.ModalAppearance +import com.atls.hyperion.ui.components.modal.style.appearance.default +import com.atls.hyperion.ui.components.modal.style.shape.ModalShape +import com.atls.hyperion.ui.components.modal.style.shape.popup + +@Composable +fun Popup( + modifier: Modifier = Modifier, + appearance: ModalAppearance = ModalAppearance.default(), + shape: ModalShape = ModalShape.popup(), + onDismissRequest: () -> Unit, + content: @Composable () -> Unit +) { + Dialog( + onDismissRequest = onDismissRequest, + properties = DialogProperties( + usePlatformDefaultWidth = false + ) + ) { + Box( + modifier = modifier + .padding(shape.spacers) + .background( + color = appearance.backgroundColor, + shape = shape.shape + ) + .fillMaxWidth() + .padding(shape.paddings) + ) { + content() + } + } +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/stories/Component.kt new file mode 100644 index 000000000..378158877 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/popup/stories/Component.kt @@ -0,0 +1,63 @@ +package com.atls.hyperion.ui.components.modal.popup.stories + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.ui.components.button.Button +import com.atls.hyperion.ui.components.button.styles.appearance.ButtonAppearance +import com.atls.hyperion.ui.components.button.styles.appearance.blue +import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape +import com.atls.hyperion.ui.components.button.styles.shape.normal +import com.atls.hyperion.ui.components.modal.popup.Popup +import com.atls.hyperion.ui.theme.tokens.layout.Space + +class PopupStory : ComponentExample { + override val name: String = "Popup" + + @Composable + override fun Content() { + var showDialog by remember { mutableStateOf(false) } + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(Space.g12) + ) { + Button( + text = "Show Popup", + appearance = ButtonAppearance.blue(), + shape = ButtonShape.normal(), + onClick = { showDialog = true } + ) + + if (showDialog) { + Popup( + onDismissRequest = { showDialog = false } + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(Space.g16) + ) { + Text(text = "This is a Popup Dialog") + Button( + modifier = Modifier.padding(top = Space.g12), + text = "Close", + appearance = ButtonAppearance.blue(), + shape = ButtonShape.normal(), + onClick = { showDialog = false } + ) + } + } + } + } + } +} From 90c4ea2de764da415d58aac97b2ea2042357108f Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:58:34 +0300 Subject: [PATCH 65/75] feat(ui): date picker stories --- .../fragment/datepicker/stories/Component.kt | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/stories/Component.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/stories/Component.kt new file mode 100644 index 000000000..39b06502e --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/stories/Component.kt @@ -0,0 +1,69 @@ +package com.atls.hyperion.ui.fragment.datepicker.stories + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.atls.hyperion.storybook.shared.model.ComponentExample +import com.atls.hyperion.ui.fragment.datepicker.DatePicker +import com.atls.hyperion.ui.fragment.datepicker.model.DateSelection + +class DatePickerStory( + override val name: String = "Date picker" +) : ComponentExample { + + @Composable + override fun Content() { + var selection by remember { + mutableStateOf(DateSelection.Single(null)) + } + + Column(Modifier.padding(16.dp)) { + Text( + text = when (val s = selection) { + is DateSelection.Single -> "Selected: ${s.date ?: "null"}" + else -> "Unexpected state" + } + ) + + DatePicker( + selection = selection, + onSelectionChange = { selection = it }, + onDismiss = {} + ) + } + } +} + +class DateRangePickerStory( + override val name: String = "Date range picker" +) : ComponentExample { + + @Composable + override fun Content() { + var selection by remember { + mutableStateOf(DateSelection.Range(null, null)) + } + + Column(Modifier.padding(16.dp)) { + Text( + text = when (val s = selection) { + is DateSelection.Range -> "From: ${s.start ?: "null"} To: ${s.end ?: "null"}" + else -> "Unexpected state" + } + ) + + DatePicker( + selection = selection, + onSelectionChange = { selection = it }, + onDismiss = {} + ) + } + } +} From 66b844c11bdefdb4eddfa40c597410588740325a Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:58:52 +0300 Subject: [PATCH 66/75] feat(ui): date/calendar deps --- mobile/kmp/ui/build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mobile/kmp/ui/build.gradle.kts b/mobile/kmp/ui/build.gradle.kts index 06e228750..4aeef3e65 100644 --- a/mobile/kmp/ui/build.gradle.kts +++ b/mobile/kmp/ui/build.gradle.kts @@ -34,12 +34,15 @@ kotlin { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) + implementation(compose.material3) implementation(compose.ui) implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) implementation(libs.compose.shadow) implementation(libs.coil.compose) implementation(libs.coil.network.ktor) + implementation(libs.compose.calendar) + api(libs.kotlinx.datetime) } androidMain { From 6633cda071553deaeb4124ab9d645a16c59da8e9 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 04:59:12 +0300 Subject: [PATCH 67/75] chore(storybook): spacing for component variants --- .../com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt index c0e6bb68b..dab73d455 100644 --- a/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt +++ b/mobile/kmp/storybook/src/commonMain/kotlin/com/atls/hyperion/storybook/shared/ui/ComponentVariants.kt @@ -3,8 +3,10 @@ package com.atls.hyperion.storybook.shared.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.Divider @@ -55,6 +57,7 @@ fun ComponentVariants( fontSize = FontSize.small, modifier = Modifier.padding(top = Padding.tiny) ) + Spacer(Modifier.width(Padding.small)) content(appearanceProvider(), shapeProvider()) } Divider() From 5bbdcc52d06c191dabe7b81d8f967aa55cb6a427 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 05:00:17 +0300 Subject: [PATCH 68/75] chore(deps): toml update --- mobile/kmp/gradle/libs.versions.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mobile/kmp/gradle/libs.versions.toml b/mobile/kmp/gradle/libs.versions.toml index 9552d8258..40c85d346 100644 --- a/mobile/kmp/gradle/libs.versions.toml +++ b/mobile/kmp/gradle/libs.versions.toml @@ -1,13 +1,17 @@ [versions] +calendar = "2.9.0" kotlin = "2.2.0" ktor = "3.3.1" compose = "1.10.0-rc02" composeShadow = "2.0.4" coilCompose = "3.3.0" +kotlinxDatetime = "0.6.1" agp = "8.9.0" androidx-activityCompose = "1.9.3" [libraries] +compose-calendar = { module = "com.kizitonwose.calendar:compose-multiplatform", version.ref = "calendar" } +kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } compose-shadow = { module = "com.adamglin:compose-shadow", version.ref = "composeShadow" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" } From 3834a64e5f27b35c1994382188382af02514af07 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 05:00:30 +0300 Subject: [PATCH 69/75] feat(app): new stories usage --- .../src/commonMain/kotlin/com/atls/hyperion/sample/App.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt index 4678edce3..cfcc0b92e 100644 --- a/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt +++ b/mobile/kmp/sample/src/commonMain/kotlin/com/atls/hyperion/sample/App.kt @@ -9,7 +9,11 @@ import com.atls.hyperion.ui.components.card.stories.CardStory import com.atls.hyperion.ui.components.checkbox.stories.CheckboxStory import com.atls.hyperion.ui.components.divider.stories.DividerStory import com.atls.hyperion.ui.components.input.stories.InputStory +import com.atls.hyperion.ui.components.modal.bottom.stories.BottomDialogStory +import com.atls.hyperion.ui.components.modal.popup.stories.PopupStory import com.atls.hyperion.ui.components.switch.stories.SwitchStory +import com.atls.hyperion.ui.fragment.datepicker.stories.DatePickerStory +import com.atls.hyperion.ui.fragment.datepicker.stories.DateRangePickerStory import com.atls.hyperion.ui.primitives.stories.LinkStory import com.atls.hyperion.ui.primitives.stories.TextStory @@ -19,10 +23,14 @@ fun App() { Storybook( components = listOf( AvatarStory(), + BottomDialogStory(), ButtonStory(), CheckboxStory(), + DatePickerStory(), + DateRangePickerStory(), DividerStory(), InputStory(), + PopupStory(), SwitchStory(), CardStory(), TextStory(), From fe5a744c1b10a74b478b26b4853054730d4316d8 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Tue, 13 Jan 2026 13:44:54 +0300 Subject: [PATCH 70/75] chore(input): remove todo --- .../hyperion/ui/components/input/style/appearance/Variants.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt index 5c64c68ed..32f59a713 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/input/style/appearance/Variants.kt @@ -10,7 +10,7 @@ fun InputAppearance.Companion.blue(): InputAppearance = filled = Colors.fromColorSet(TokenColors.Input.Blue.Default), focused = Colors.fromColorSet(TokenColors.Input.Blue.Focus), disabled = Colors.fromColorSet(TokenColors.Input.Blue.Disabled), - error = Colors.fromColorSet(TokenColors.Input.Blue.Default), // TODO: Add error colors to tokens + error = Colors.fromColorSet(TokenColors.Input.Blue.Default), active = Colors.fromColorSet(TokenColors.Input.Blue.Active) ) @@ -21,6 +21,6 @@ fun InputAppearance.Companion.white(): InputAppearance = filled = Colors.fromColorSet(TokenColors.Input.White.Default), focused = Colors.fromColorSet(TokenColors.Input.White.Focus), disabled = Colors.fromColorSet(TokenColors.Input.White.Disabled), - error = Colors.fromColorSet(TokenColors.Input.White.Default), // TODO: Add error colors to tokens + error = Colors.fromColorSet(TokenColors.Input.White.Default), active = Colors.fromColorSet(TokenColors.Input.White.Active) ) From 2a990919220d478f127c731e3130caa4a5700b95 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Wed, 14 Jan 2026 01:40:10 +0300 Subject: [PATCH 71/75] refactor(ui): move sizes from theme --- .../kotlin/com/atls/hyperion/ui/components/avatar/Component.kt | 2 +- .../atls/hyperion/ui/components/avatar/styles/shape/Variants.kt | 2 +- .../CheckboxSize.kt => components/checkbox/styles/Size.kt} | 2 +- .../hyperion/ui/components/checkbox/styles/shape/Variants.kt | 2 +- .../hyperion/ui/primitives/{Image.kt => image/Primitive.kt} | 2 +- .../tokens/components/ImageSize.kt => primitives/image/Size.kt} | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/{theme/tokens/components/CheckboxSize.kt => components/checkbox/styles/Size.kt} (69%) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/{Image.kt => image/Primitive.kt} (96%) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/{theme/tokens/components/ImageSize.kt => primitives/image/Size.kt} (70%) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt index e6648273e..95de6f357 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/Component.kt @@ -8,7 +8,7 @@ import androidx.compose.ui.layout.ContentScale import coil3.compose.AsyncImage import com.atls.hyperion.ui.components.avatar.styles.appearance.AvatarAppearance import com.atls.hyperion.ui.components.avatar.styles.shape.AvatarShape -import com.atls.hyperion.ui.primitives.Image +import com.atls.hyperion.ui.primitives.image.Image @Composable fun Avatar( diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt index 3a90330cf..53c6f0e19 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/avatar/styles/shape/Variants.kt @@ -1,7 +1,7 @@ package com.atls.hyperion.ui.components.avatar.styles.shape import androidx.compose.runtime.Composable -import com.atls.hyperion.ui.theme.tokens.components.ImageSize +import com.atls.hyperion.ui.primitives.image.ImageSize import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius @Composable diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/CheckboxSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/Size.kt similarity index 69% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/CheckboxSize.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/Size.kt index b487fc00b..c16334ee5 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/CheckboxSize.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/Size.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.theme.tokens.components +package com.atls.hyperion.ui.components.checkbox.styles import androidx.compose.ui.unit.dp diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt index 9c5c921f0..9b7490026 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/styles/shape/Variants.kt @@ -1,6 +1,6 @@ package com.atls.hyperion.ui.components.checkbox.styles.shape -import com.atls.hyperion.ui.theme.tokens.components.CheckboxSize +import com.atls.hyperion.ui.components.checkbox.styles.CheckboxSize import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Image.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/image/Primitive.kt similarity index 96% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Image.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/image/Primitive.kt index c67176d2f..5d95b53db 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Image.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/image/Primitive.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.primitives +package com.atls.hyperion.ui.primitives.image import androidx.compose.foundation.Image import androidx.compose.runtime.Composable diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/ImageSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/image/Size.kt similarity index 70% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/ImageSize.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/image/Size.kt index 4467d79de..46ce977a8 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/ImageSize.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/image/Size.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.theme.tokens.components +package com.atls.hyperion.ui.primitives.image import androidx.compose.ui.unit.dp From 3c881b1364c0e4030b8fd9aa2b67d0f5af32942e Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Wed, 14 Jan 2026 01:52:41 +0300 Subject: [PATCH 72/75] refactor(ui): move alpha from colors to effects --- .../atls/hyperion/ui/theme/tokens/{colors => effects}/Alpha.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/{colors => effects}/Alpha.kt (61%) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/effects/Alpha.kt similarity index 61% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/effects/Alpha.kt index ae0441a7a..6ef296fef 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/colors/Alpha.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/effects/Alpha.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.theme.tokens.colors +package com.atls.hyperion.ui.theme.tokens.effects object Alpha { val huge = 0.9f From beea2023f00d5b536fc9e2e27b2d23019c3eed81 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Wed, 14 Jan 2026 01:55:22 +0300 Subject: [PATCH 73/75] refactor(theme): move component sizes to components --- .../com/atls/hyperion/ui/components/checkbox/Component.kt | 2 +- .../modal/bottom/dragHandle/style/Size.kt} | 2 +- .../components/modal/bottom/dragHandle/style/shape/Variants.kt | 2 +- .../SwitchSize.kt => components/switch/styles/Size.kt} | 2 +- .../atls/hyperion/ui/components/switch/styles/shape/Variants.kt | 2 +- .../hyperion/ui/fragment/datepicker/style/shape/Variants.kt | 2 +- .../atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt | 2 +- .../atls/hyperion/ui/primitives/{Icon.kt => icon/Primitive.kt} | 2 +- .../tokens/components/IconSize.kt => primitives/icon/Size.kt} | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/{theme/tokens/components/DragHandleSize.kt => components/modal/bottom/dragHandle/style/Size.kt} (68%) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/{theme/tokens/components/SwitchSize.kt => components/switch/styles/Size.kt} (73%) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/{Icon.kt => icon/Primitive.kt} (92%) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/{theme/tokens/components/IconSize.kt => primitives/icon/Size.kt} (60%) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt index f09cb7708..f0f1c2bf7 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/checkbox/Component.kt @@ -16,7 +16,7 @@ import com.atls.hyperion.ui.components.checkbox.locals.LocalState import com.atls.hyperion.ui.components.checkbox.state.State import com.atls.hyperion.ui.components.checkbox.styles.appearance.CheckboxAppearance import com.atls.hyperion.ui.components.checkbox.styles.shape.CheckboxShape -import com.atls.hyperion.ui.primitives.Icon +import com.atls.hyperion.ui.primitives.icon.Icon import com.atls.hyperion.ui.theme.tokens.layout.Weight @Composable diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/DragHandleSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/Size.kt similarity index 68% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/DragHandleSize.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/Size.kt index c21fa6ed0..a442f8a74 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/DragHandleSize.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/Size.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.theme.tokens.components +package com.atls.hyperion.ui.components.modal.bottom.dragHandle.style import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt index 8fc610a60..ed2d95e21 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/bottom/dragHandle/style/shape/Variants.kt @@ -2,7 +2,7 @@ package com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.shape import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable -import com.atls.hyperion.ui.theme.tokens.components.DragHandleSize +import com.atls.hyperion.ui.components.modal.bottom.dragHandle.style.DragHandleSize import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius import com.atls.hyperion.ui.theme.tokens.layout.Space diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/SwitchSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/Size.kt similarity index 73% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/SwitchSize.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/Size.kt index 72132862e..d0be7b9ec 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/SwitchSize.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/Size.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.theme.tokens.components +package com.atls.hyperion.ui.components.switch.styles import androidx.compose.ui.unit.dp diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt index 15e5b743a..bda4ed823 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/switch/styles/shape/Variants.kt @@ -1,6 +1,6 @@ package com.atls.hyperion.ui.components.switch.styles.shape -import com.atls.hyperion.ui.theme.tokens.components.SwitchSize +import com.atls.hyperion.ui.components.switch.styles.SwitchSize import com.atls.hyperion.ui.theme.tokens.layout.Space fun SwitchShape.Companion.medium(): SwitchShape = diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt index 9ad908e0f..d4e609587 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt @@ -9,7 +9,7 @@ import com.atls.hyperion.ui.components.divider.style.shape.default import com.atls.hyperion.ui.components.modal.style.shape.ModalShape import com.atls.hyperion.ui.components.modal.style.shape.popup import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition -import com.atls.hyperion.ui.theme.tokens.components.IconSize +import com.atls.hyperion.ui.primitives.icon.IconSize import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius import com.atls.hyperion.ui.theme.tokens.layout.Space import com.atls.hyperion.ui.theme.typography.FontSize diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt index 7fda72508..a7a1d8772 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt @@ -16,9 +16,9 @@ import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape import com.atls.hyperion.ui.generated.resources.Res import com.atls.hyperion.ui.generated.resources.chevron_left import com.atls.hyperion.ui.generated.resources.chevron_right -import com.atls.hyperion.ui.primitives.Icon import com.atls.hyperion.ui.primitives.Text import com.atls.hyperion.ui.primitives.VerticalSpacer +import com.atls.hyperion.ui.primitives.icon.Icon import org.jetbrains.compose.resources.painterResource @Composable diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Icon.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/icon/Primitive.kt similarity index 92% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Icon.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/icon/Primitive.kt index 9aafb876d..2f9897700 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/Icon.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/icon/Primitive.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.primitives +package com.atls.hyperion.ui.primitives.icon import androidx.compose.foundation.layout.size import androidx.compose.material.Icon diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/IconSize.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/icon/Size.kt similarity index 60% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/IconSize.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/icon/Size.kt index 33bd8f36b..8e6faec47 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/components/IconSize.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/primitives/icon/Size.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.theme.tokens.components +package com.atls.hyperion.ui.primitives.icon import androidx.compose.ui.unit.dp From 7150f6d67e95e4f977eb2aae0729b4a7c2f0dde9 Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Wed, 14 Jan 2026 01:56:06 +0300 Subject: [PATCH 74/75] refactor(theme): move elevation tokens to layout --- .../kotlin/com/atls/hyperion/ui/components/button/Layout.kt | 2 +- .../ui/components/button/styles/appearance/Appearance.kt | 2 +- .../hyperion/ui/components/card/style/appearance/Appearance.kt | 2 +- .../atls/hyperion/ui/components/modal/style/shape/Variants.kt | 2 +- .../com/atls/hyperion/ui/theme/tokens/{ => layout}/Elevation.kt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/{ => layout}/Elevation.kt (66%) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt index 5e41c0509..3077aaab7 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/Layout.kt @@ -23,7 +23,7 @@ import com.atls.hyperion.ui.components.button.styles.appearance.Colors import com.atls.hyperion.ui.components.button.styles.shape.ButtonShape import com.atls.hyperion.ui.shared.addon.AddonPosition import com.atls.hyperion.ui.shared.addon.AddonSlotManager -import com.atls.hyperion.ui.theme.tokens.Elevation +import com.atls.hyperion.ui.theme.tokens.layout.Elevation import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors @OptIn(ExperimentalMaterialApi::class) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt index 5a2048b9e..1c1b0db9c 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/button/styles/appearance/Appearance.kt @@ -2,7 +2,7 @@ package com.atls.hyperion.ui.components.button.styles.appearance import androidx.compose.ui.unit.Dp import com.atls.hyperion.ui.components.button.state.ButtonState -import com.atls.hyperion.ui.theme.tokens.Elevation +import com.atls.hyperion.ui.theme.tokens.layout.Elevation data class ButtonAppearance( val default: Colors, diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt index 8af36bcc7..1f874708c 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/card/style/appearance/Appearance.kt @@ -2,7 +2,7 @@ package com.atls.hyperion.ui.components.card.style.appearance import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp -import com.atls.hyperion.ui.theme.tokens.Elevation +import com.atls.hyperion.ui.theme.tokens.layout.Elevation import com.atls.hyperion.ui.theme.tokens.colors.Colors as ThemeColors data class CardAppearance( diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt index ea3f71b06..dd33044dc 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/modal/style/shape/Variants.kt @@ -3,8 +3,8 @@ package com.atls.hyperion.ui.components.modal.style.shape import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable -import com.atls.hyperion.ui.theme.tokens.Elevation import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Elevation import com.atls.hyperion.ui.theme.tokens.layout.Space @Composable diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Elevation.kt similarity index 66% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Elevation.kt index 871c26c28..29d13b027 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/Elevation.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/theme/tokens/layout/Elevation.kt @@ -1,4 +1,4 @@ -package com.atls.hyperion.ui.theme.tokens +package com.atls.hyperion.ui.theme.tokens.layout import androidx.compose.ui.unit.dp From 2c206155d4709e738dd3da7660f59a62f24d215e Mon Sep 17 00:00:00 2001 From: Arina Gazhina Date: Wed, 14 Jan 2026 02:26:57 +0300 Subject: [PATCH 75/75] refactor(picker): split styles --- .../ui/fragment/datepicker/Fragment.kt | 4 +- .../datepicker/style/appearance/Appearance.kt | 27 ------------ .../datepicker/style/appearance/Cell.kt | 18 ++++++++ .../datepicker/style/appearance/Header.kt | 10 +++++ .../datepicker/style/appearance/Picker.kt | 17 ++++++++ .../datepicker/style/appearance/WeekDays.kt | 9 ++++ .../style/appearance/variants/Cell.kt | 17 ++++++++ .../style/appearance/variants/Header.kt | 12 ++++++ .../{Variants.kt => variants/Picker.kt} | 19 ++++---- .../style/appearance/variants/WeekDays.kt | 11 +++++ .../datepicker/style/shape/Calendar.kt | 15 +++++++ .../fragment/datepicker/style/shape/Cell.kt | 22 ++++++++++ .../fragment/datepicker/style/shape/Header.kt | 13 ++++++ .../fragment/datepicker/style/shape/Shape.kt | 31 ++----------- .../datepicker/style/shape/Variants.kt | 43 ------------------- .../style/shape/variants/Calendar.kt | 20 +++++++++ .../datepicker/style/shape/variants/Cell.kt | 26 +++++++++++ .../datepicker/style/shape/variants/Header.kt | 21 +++++++++ .../datepicker/style/shape/variants/Picker.kt | 15 +++++++ .../fragment/datepicker/ui/CalendarHeader.kt | 26 +++++------ .../datepicker/ui/DatePickerContent.kt | 2 +- .../hyperion/ui/fragment/datepicker/ui/Day.kt | 42 +++++++++--------- .../ui/fragment/datepicker/ui/WeekDays.kt | 4 +- 23 files changed, 276 insertions(+), 148 deletions(-) delete mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Cell.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Header.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Picker.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/WeekDays.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Cell.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Header.kt rename mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/{Variants.kt => variants/Picker.kt} (59%) create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/WeekDays.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Calendar.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Cell.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Header.kt delete mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Calendar.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Cell.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Header.kt create mode 100644 mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Picker.kt diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt index 6d08c55c4..6fa36b2df 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/Fragment.kt @@ -5,9 +5,9 @@ import androidx.compose.ui.Modifier import com.atls.hyperion.ui.components.modal.popup.Popup import com.atls.hyperion.ui.fragment.datepicker.model.DateSelection import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance -import com.atls.hyperion.ui.fragment.datepicker.style.appearance.default +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.variants.default import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape -import com.atls.hyperion.ui.fragment.datepicker.style.shape.default +import com.atls.hyperion.ui.fragment.datepicker.style.shape.variants.default import com.atls.hyperion.ui.fragment.datepicker.ui.DatePickerContent @Composable diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt deleted file mode 100644 index cb1567a4a..000000000 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Appearance.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.atls.hyperion.ui.fragment.datepicker.style.appearance - -import androidx.compose.ui.graphics.Color -import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance -import com.atls.hyperion.ui.components.modal.style.appearance.ModalAppearance - -data class DatePickerAppearance( - val cellBackgroundColor: Color, - val cellTextColor: Color, - val cellActiveBackgroundColor: Color, - val cellActiveTextColor: Color, - val cellInRangeBackgroundColor: Color, - val cellInRangeTextColor: Color, - val cellBorderColor: Color = Color.Transparent, - val cellActiveBorderColor: Color = Color.Transparent, - val cellInRangeBorderColor: Color = Color.Transparent, - val cellHeaderTextColor: Color, - val backgroundColor: Color, - val headerTextColor: Color, - val weekDaysTextColor: Color = headerTextColor, - val arrowColor: Color, - val dividerColor: Color, - val dividerAppearance: DividerAppearance, - val modalAppearance: ModalAppearance -) { - companion object Companion -} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Cell.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Cell.kt new file mode 100644 index 000000000..bca22879b --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Cell.kt @@ -0,0 +1,18 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance + +import androidx.compose.ui.graphics.Color + +data class CellAppearance( + val backgroundColor: Color, + val textColor: Color, + val activeBackgroundColor: Color, + val activeTextColor: Color, + val inRangeBackgroundColor: Color, + val inRangeTextColor: Color, + val borderColor: Color = Color.Transparent, + val activeBorderColor: Color = Color.Transparent, + val inRangeBorderColor: Color = Color.Transparent, + val headerTextColor: Color +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Header.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Header.kt new file mode 100644 index 000000000..f1b5fc284 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Header.kt @@ -0,0 +1,10 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance + +import androidx.compose.ui.graphics.Color + +data class HeaderAppearance( + val textColor: Color, + val arrowColor: Color +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Picker.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Picker.kt new file mode 100644 index 000000000..a6f0ee657 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Picker.kt @@ -0,0 +1,17 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance + +import androidx.compose.ui.graphics.Color +import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance +import com.atls.hyperion.ui.components.modal.style.appearance.ModalAppearance + +data class DatePickerAppearance( + val cellAppearance: CellAppearance, + val headerAppearance: HeaderAppearance, + val weekDaysAppearance: WeekDaysAppearance, + val backgroundColor: Color, + val dividerColor: Color, + val dividerAppearance: DividerAppearance, + val modalAppearance: ModalAppearance +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/WeekDays.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/WeekDays.kt new file mode 100644 index 000000000..8f0b78e56 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/WeekDays.kt @@ -0,0 +1,9 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance + +import androidx.compose.ui.graphics.Color + +data class WeekDaysAppearance( + val textColor: Color +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Cell.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Cell.kt new file mode 100644 index 000000000..0119c7649 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Cell.kt @@ -0,0 +1,17 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance.variants + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.CellAppearance +import com.atls.hyperion.ui.theme.tokens.colors.Colors as TokenColors + +@Composable +fun CellAppearance.Companion.default(): CellAppearance = + CellAppearance( + backgroundColor = TokenColors.Palette.transparent, + textColor = TokenColors.Text.black, + activeBackgroundColor = TokenColors.Palette.blue, + activeTextColor = TokenColors.Text.white, + inRangeBackgroundColor = TokenColors.Palette.lightPurple, + inRangeTextColor = TokenColors.Text.black, + headerTextColor = TokenColors.Text.gray + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Header.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Header.kt new file mode 100644 index 000000000..28afb20bc --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Header.kt @@ -0,0 +1,12 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance.variants + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.HeaderAppearance +import com.atls.hyperion.ui.theme.tokens.colors.Colors as TokenColors + +@Composable +fun HeaderAppearance.Companion.default(): HeaderAppearance = + HeaderAppearance( + textColor = TokenColors.Text.black, + arrowColor = TokenColors.Text.black + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Picker.kt similarity index 59% rename from mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Variants.kt rename to mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Picker.kt index e59fdb1fa..12282c766 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/Variants.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/Picker.kt @@ -1,27 +1,24 @@ -package com.atls.hyperion.ui.fragment.datepicker.style.appearance +package com.atls.hyperion.ui.fragment.datepicker.style.appearance.variants import androidx.compose.runtime.Composable import com.atls.hyperion.ui.components.divider.style.appearance.DividerAppearance import com.atls.hyperion.ui.components.divider.style.appearance.default import com.atls.hyperion.ui.components.modal.style.appearance.ModalAppearance import com.atls.hyperion.ui.components.modal.style.appearance.default +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.CellAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.DatePickerAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.HeaderAppearance +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.WeekDaysAppearance import com.atls.hyperion.ui.theme.tokens.colors.Colors as TokenColors @Composable fun DatePickerAppearance.Companion.default(): DatePickerAppearance = DatePickerAppearance( - cellBackgroundColor = TokenColors.Palette.transparent, - cellTextColor = TokenColors.Text.black, - cellActiveBackgroundColor = TokenColors.Palette.blue, - cellActiveTextColor = TokenColors.Text.white, - cellInRangeBackgroundColor = TokenColors.Palette.lightPurple, - cellInRangeTextColor = TokenColors.Text.black, - cellHeaderTextColor = TokenColors.Text.gray, + cellAppearance = CellAppearance.default(), + headerAppearance = HeaderAppearance.default(), + weekDaysAppearance = WeekDaysAppearance.default(), backgroundColor = TokenColors.Palette.white, - headerTextColor = TokenColors.Text.black, - arrowColor = TokenColors.Text.black, dividerColor = TokenColors.Palette.gray, - weekDaysTextColor = TokenColors.Text.black, dividerAppearance = DividerAppearance.default(), modalAppearance = ModalAppearance.default() ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/WeekDays.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/WeekDays.kt new file mode 100644 index 000000000..61a3199c8 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/appearance/variants/WeekDays.kt @@ -0,0 +1,11 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.appearance.variants + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.fragment.datepicker.style.appearance.WeekDaysAppearance +import com.atls.hyperion.ui.theme.tokens.colors.Colors as TokenColors + +@Composable +fun WeekDaysAppearance.Companion.default(): WeekDaysAppearance = + WeekDaysAppearance( + textColor = TokenColors.Text.black + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Calendar.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Calendar.kt new file mode 100644 index 000000000..5644885c7 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Calendar.kt @@ -0,0 +1,15 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape + +import androidx.compose.foundation.layout.PaddingValues +import com.atls.hyperion.ui.components.divider.style.shape.DividerShape +import com.atls.hyperion.ui.components.modal.style.shape.ModalShape +import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition + +data class CalendarShape( + val padding: PaddingValues, + val divider: DividerPosition = DividerPosition.NONE, + val dividerShape: DividerShape, + val modalShape: ModalShape +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Cell.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Cell.kt new file mode 100644 index 000000000..1ff8bd822 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Cell.kt @@ -0,0 +1,22 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke + +data class CellShape( + val spacing: Dp, + val padding: Dp, + val borderWidth: Dp = BorderStroke.none, + val borderColor: Color = Color.Transparent, + val shape: Shape, + val activeShape: Shape = shape, + val rangeShape: Shape = RectangleShape, + val typography: TextStyle, + val headerTypography: TextStyle +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Header.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Header.kt new file mode 100644 index 000000000..8f3d4ad94 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Header.kt @@ -0,0 +1,13 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape + +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp + +data class HeaderShape( + val typography: TextStyle, + val spacing: Dp, + val iconSize: Dp, + val horizontalPadding: Dp +) { + companion object +} diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt index 17d915078..b552e3a92 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Shape.kt @@ -1,34 +1,9 @@ package com.atls.hyperion.ui.fragment.datepicker.style.shape -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.Dp -import com.atls.hyperion.ui.components.divider.style.shape.DividerShape -import com.atls.hyperion.ui.components.modal.style.shape.ModalShape -import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition -import com.atls.hyperion.ui.theme.tokens.layout.BorderStroke - data class DatePickerShape( - val cellSpacing: Dp, - val cellPadding: Dp, - val cellBorderWidth: Dp = BorderStroke.none, - val cellBorderColor: Color = Color.Transparent, - val cellShape: Shape, - val cellActiveShape: Shape = cellShape, - val cellRangeShape: Shape = RectangleShape, - val cellTypography: TextStyle, - val headerTypography: TextStyle, - val headerSpacing: Dp, - val calendarPadding: PaddingValues, - val dayHeaderTypography: TextStyle, - val headerIconSize: Dp, - val headerHorizontalPadding: Dp, - val divider: DividerPosition = DividerPosition.NONE, - val dividerShape: DividerShape, - val modalShape: ModalShape + val cellShape: CellShape, + val headerShape: HeaderShape, + val calendarShape: CalendarShape ) { companion object Companion } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt deleted file mode 100644 index d4e609587..000000000 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/Variants.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.atls.hyperion.ui.fragment.datepicker.style.shape - -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.ui.text.TextStyle -import com.atls.hyperion.ui.components.divider.style.shape.DividerShape -import com.atls.hyperion.ui.components.divider.style.shape.default -import com.atls.hyperion.ui.components.modal.style.shape.ModalShape -import com.atls.hyperion.ui.components.modal.style.shape.popup -import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition -import com.atls.hyperion.ui.primitives.icon.IconSize -import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius -import com.atls.hyperion.ui.theme.tokens.layout.Space -import com.atls.hyperion.ui.theme.typography.FontSize -import com.atls.hyperion.ui.theme.typography.FontWeight - -@Composable -fun DatePickerShape.Companion.default(): DatePickerShape = - DatePickerShape( - cellTypography = TextStyle( - fontSize = FontSize.xs, - fontWeight = FontWeight.regular, - ), - headerTypography = TextStyle( - fontSize = FontSize.md, - fontWeight = FontWeight.bold, - ), - dayHeaderTypography = TextStyle( - fontSize = FontSize.xs2, - fontWeight = FontWeight.medium, - ), - cellSpacing = Space.zero, - cellPadding = Space.g8, - cellShape = RoundedCornerShape(CornerRadius.xs2), - calendarPadding = PaddingValues(Space.g12), - headerIconSize = IconSize.medium, - headerSpacing = Space.g12, - headerHorizontalPadding = Space.g12, - divider = DividerPosition.BOTTOM, - dividerShape = DividerShape.default(), - modalShape = ModalShape.popup() - ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Calendar.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Calendar.kt new file mode 100644 index 000000000..9c0f0fc14 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Calendar.kt @@ -0,0 +1,20 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape.variants + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.components.divider.style.shape.DividerShape +import com.atls.hyperion.ui.components.divider.style.shape.default +import com.atls.hyperion.ui.components.modal.style.shape.ModalShape +import com.atls.hyperion.ui.components.modal.style.shape.popup +import com.atls.hyperion.ui.fragment.datepicker.model.DividerPosition +import com.atls.hyperion.ui.fragment.datepicker.style.shape.CalendarShape +import com.atls.hyperion.ui.theme.tokens.layout.Space + +@Composable +fun CalendarShape.Companion.default(): CalendarShape = + CalendarShape( + padding = PaddingValues(Space.g12), + divider = DividerPosition.BOTTOM, + dividerShape = DividerShape.default(), + modalShape = ModalShape.popup() + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Cell.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Cell.kt new file mode 100644 index 000000000..9488b92a8 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Cell.kt @@ -0,0 +1,26 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape.variants + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import com.atls.hyperion.ui.fragment.datepicker.style.shape.CellShape +import com.atls.hyperion.ui.theme.tokens.layout.CornerRadius +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.typography.FontSize +import com.atls.hyperion.ui.theme.typography.FontWeight + +@Composable +fun CellShape.Companion.default(): CellShape = + CellShape( + spacing = Space.zero, + padding = Space.g8, + shape = RoundedCornerShape(CornerRadius.xs2), + typography = TextStyle( + fontSize = FontSize.xs, + fontWeight = FontWeight.regular, + ), + headerTypography = TextStyle( + fontSize = FontSize.xs2, + fontWeight = FontWeight.medium, + ) + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Header.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Header.kt new file mode 100644 index 000000000..f95c7a479 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Header.kt @@ -0,0 +1,21 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape.variants + +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import com.atls.hyperion.ui.fragment.datepicker.style.shape.HeaderShape +import com.atls.hyperion.ui.primitives.icon.IconSize +import com.atls.hyperion.ui.theme.tokens.layout.Space +import com.atls.hyperion.ui.theme.typography.FontSize +import com.atls.hyperion.ui.theme.typography.FontWeight + +@Composable +fun HeaderShape.Companion.default(): HeaderShape = + HeaderShape( + typography = TextStyle( + fontSize = FontSize.md, + fontWeight = FontWeight.bold, + ), + spacing = Space.g12, + iconSize = IconSize.medium, + horizontalPadding = Space.g12 + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Picker.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Picker.kt new file mode 100644 index 000000000..5746a0e12 --- /dev/null +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/style/shape/variants/Picker.kt @@ -0,0 +1,15 @@ +package com.atls.hyperion.ui.fragment.datepicker.style.shape.variants + +import androidx.compose.runtime.Composable +import com.atls.hyperion.ui.fragment.datepicker.style.shape.CalendarShape +import com.atls.hyperion.ui.fragment.datepicker.style.shape.CellShape +import com.atls.hyperion.ui.fragment.datepicker.style.shape.DatePickerShape +import com.atls.hyperion.ui.fragment.datepicker.style.shape.HeaderShape + +@Composable +fun DatePickerShape.Companion.default(): DatePickerShape = + DatePickerShape( + cellShape = CellShape.default(), + headerShape = HeaderShape.default(), + calendarShape = CalendarShape.default() + ) diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt index a7a1d8772..1d82b3a63 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/CalendarHeader.kt @@ -33,47 +33,47 @@ fun CalendarHeader( onPrevMonth: () -> Unit, onNextMonth: () -> Unit, ) { - if (shape.divider == DividerPosition.TOP) { + if (shape.calendarShape.divider == DividerPosition.TOP) { HorizontalDivider( appearance = appearance.dividerAppearance, - shape = shape.dividerShape + shape = shape.calendarShape.dividerShape ) - VerticalSpacer(shape.headerSpacing) + VerticalSpacer(shape.headerShape.spacing) } Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = shape.headerHorizontalPadding), + .padding(horizontal = shape.headerShape.horizontalPadding), horizontalArrangement = arrangement, verticalAlignment = alignment ) { Icon( icon = beforeIcon, - size = shape.headerIconSize, + size = shape.headerShape.iconSize, modifier = Modifier.clickable { onPrevMonth() }, - color = appearance.arrowColor + color = appearance.headerAppearance.arrowColor ) Text( text = monthName, - typography = shape.headerTypography, - color = appearance.headerTextColor + typography = shape.headerShape.typography, + color = appearance.headerAppearance.textColor ) Icon( icon = afterIcon, - size = shape.headerIconSize, + size = shape.headerShape.iconSize, modifier = Modifier.clickable { onNextMonth() }, - color = appearance.arrowColor + color = appearance.headerAppearance.arrowColor ) } - if (shape.divider == DividerPosition.BOTTOM) { - VerticalSpacer(shape.headerSpacing) + if (shape.calendarShape.divider == DividerPosition.BOTTOM) { + VerticalSpacer(shape.headerShape.spacing) HorizontalDivider( appearance = appearance.dividerAppearance, - shape = shape.dividerShape + shape = shape.calendarShape.dividerShape ) } } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt index 104b54bfa..3e010b20c 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/DatePickerContent.kt @@ -80,7 +80,7 @@ fun DatePickerContent( HorizontalCalendar( modifier = Modifier .fillMaxWidth() - .padding(shape.calendarPadding), + .padding(shape.calendarShape.padding), state = state, dayContent = { day -> diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt index 4c9b836cd..72a8237cd 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/Day.kt @@ -38,47 +38,47 @@ fun Day( val date = LocalDate(day.date.year, day.date.monthNumber, day.date.dayOfMonth) val backgroundColor = when { - isSelected || isRangeStart || isRangeEnd -> appearance.cellActiveBackgroundColor - isInRange -> appearance.cellInRangeBackgroundColor - else -> appearance.cellBackgroundColor + isSelected || isRangeStart || isRangeEnd -> appearance.cellAppearance.activeBackgroundColor + isInRange -> appearance.cellAppearance.inRangeBackgroundColor + else -> appearance.cellAppearance.backgroundColor } val cellShape = when { - isSelected -> shape.cellActiveShape - isInRange -> shape.cellRangeShape - else -> shape.cellShape + isSelected -> shape.cellShape.activeShape + isInRange -> shape.cellShape.rangeShape + else -> shape.cellShape.shape } val textColor = when { - isSelected || isRangeStart || isRangeEnd -> appearance.cellActiveTextColor - isInRange -> appearance.cellInRangeTextColor - else -> appearance.cellTextColor + isSelected || isRangeStart || isRangeEnd -> appearance.cellAppearance.activeTextColor + isInRange -> appearance.cellAppearance.inRangeTextColor + else -> appearance.cellAppearance.textColor } val containerModifier = Modifier .aspectSquare() - .padding(shape.cellSpacing) + .padding(shape.cellShape.spacing) .clip(cellShape) .background(backgroundColor) - .padding(shape.cellPadding) + .padding(shape.cellShape.padding) .then( - if ((isSelected || isRangeStart || isRangeEnd) && appearance.cellActiveBorderColor != Colors.Palette.transparent) + if ((isSelected || isRangeStart || isRangeEnd) && appearance.cellAppearance.activeBorderColor != Colors.Palette.transparent) Modifier.border( - shape.cellBorderWidth, - appearance.cellActiveBorderColor, + shape.cellShape.borderWidth, + appearance.cellAppearance.activeBorderColor, cellShape ) - else if (isInRange && appearance.cellInRangeBorderColor != Colors.Palette.transparent) + else if (isInRange && appearance.cellAppearance.inRangeBorderColor != Colors.Palette.transparent) Modifier.border( - shape.cellBorderWidth, - appearance.cellInRangeBorderColor, + shape.cellShape.borderWidth, + appearance.cellAppearance.inRangeBorderColor, cellShape ) - else if (appearance.cellBorderColor != Colors.Palette.transparent) + else if (appearance.cellAppearance.borderColor != Colors.Palette.transparent) Modifier.border( - shape.cellBorderWidth, - appearance.cellBorderColor, + shape.cellShape.borderWidth, + appearance.cellAppearance.borderColor, cellShape ) else Modifier @@ -93,7 +93,7 @@ fun Day( Text( text = day.date.dayOfMonth.toString(), color = textColor, - typography = shape.cellTypography + typography = shape.cellShape.typography ) } } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt index dcf60fd70..d4a355a18 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/fragment/datepicker/ui/WeekDays.kt @@ -31,8 +31,8 @@ fun WeekDays( modifier = Modifier.weight(Weight.full), textAlign = TextAlign.Center, text = shortName, - typography = shape.dayHeaderTypography, - color = appearance.weekDaysTextColor, + typography = shape.cellShape.headerTypography, + color = appearance.weekDaysAppearance.textColor, ) } }