diff --git a/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/ext/Modifier.kt b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/ext/Modifier.kt
new file mode 100644
index 00000000..f4195ba7
--- /dev/null
+++ b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/ext/Modifier.kt
@@ -0,0 +1,42 @@
+package com.goalpanzi.mission_mate.core.designsystem.ext
+
+import android.graphics.BlurMaskFilter
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Paint
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.drawOutline
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+fun Modifier.dropShadow(
+ shape: Shape,
+ color: Color = Color.Black.copy(0.1f),
+ blur: Dp = 4.dp,
+ offsetY: Dp = 0.dp,
+ offsetX: Dp = 0.dp,
+ spread: Dp = 0.dp
+) = this.drawBehind {
+
+ val shadowSize = Size(size.width + spread.toPx(), size.height + spread.toPx())
+ val shadowOutline = shape.createOutline(shadowSize, layoutDirection, this)
+
+ val paint = Paint()
+ paint.color = color
+
+ if (blur.toPx() > 0) {
+ paint.asFrameworkPaint().apply {
+ maskFilter = BlurMaskFilter(blur.toPx(), BlurMaskFilter.Blur.NORMAL)
+ }
+ }
+
+ drawIntoCanvas { canvas ->
+ canvas.save()
+ canvas.translate(offsetX.toPx(), offsetY.toPx())
+ canvas.drawOutline(shadowOutline, paint)
+ canvas.restore()
+ }
+}
\ No newline at end of file
diff --git a/core/designsystem/src/main/res/drawable/background_jeju.png b/core/designsystem/src/main/res/drawable/background_jeju.png
new file mode 100644
index 00000000..b9c2f1b4
Binary files /dev/null and b/core/designsystem/src/main/res/drawable/background_jeju.png differ
diff --git a/core/designsystem/src/main/res/drawable/background_jeju_theme.png b/core/designsystem/src/main/res/drawable/background_jeju_theme.png
new file mode 100644
index 00000000..a1fd5147
Binary files /dev/null and b/core/designsystem/src/main/res/drawable/background_jeju_theme.png differ
diff --git a/core/designsystem/src/main/res/drawable/ic_creating_board.xml b/core/designsystem/src/main/res/drawable/ic_creating_board.xml
new file mode 100644
index 00000000..57d2aa51
--- /dev/null
+++ b/core/designsystem/src/main/res/drawable/ic_creating_board.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/core/designsystem/src/main/res/drawable/ic_invitation_friend.xml b/core/designsystem/src/main/res/drawable/ic_invitation_friend.xml
new file mode 100644
index 00000000..7ce3efb8
--- /dev/null
+++ b/core/designsystem/src/main/res/drawable/ic_invitation_friend.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
diff --git a/core/designsystem/src/main/res/drawable/ic_setting.xml b/core/designsystem/src/main/res/drawable/ic_setting.xml
new file mode 100644
index 00000000..cbe860e1
--- /dev/null
+++ b/core/designsystem/src/main/res/drawable/ic_setting.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/core/designsystem/src/main/res/drawable/image_onboarding_jeju.png b/core/designsystem/src/main/res/drawable/image_onboarding_jeju.png
new file mode 100644
index 00000000..71af63aa
Binary files /dev/null and b/core/designsystem/src/main/res/drawable/image_onboarding_jeju.png differ
diff --git a/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/RouteModel.kt b/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/RouteModel.kt
index d0ad89be..7b36c68e 100644
--- a/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/RouteModel.kt
+++ b/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/RouteModel.kt
@@ -5,4 +5,15 @@ import kotlinx.serialization.Serializable
sealed interface RouteModel {
@Serializable
data object Login : RouteModel
+
+ @Serializable
+ data object Onboarding : RouteModel
+}
+
+sealed interface OnboardingRouteModel {
+ @Serializable
+ data object BoardSetup : OnboardingRouteModel
+
+ @Serializable
+ data object InvitationCode : OnboardingRouteModel
}
\ No newline at end of file
diff --git a/feature/main/build.gradle.kts b/feature/main/build.gradle.kts
index dba8b50c..a6a0df44 100644
--- a/feature/main/build.gradle.kts
+++ b/feature/main/build.gradle.kts
@@ -70,4 +70,5 @@ dependencies {
implementation(project(":core:navigation"))
implementation(project(":core:domain"))
implementation(project(":feature:login"))
+ implementation(project(":feature:onboarding"))
}
\ No newline at end of file
diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt
index d76c4a9c..fc0cb642 100644
--- a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt
+++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt
@@ -9,6 +9,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import com.goalpanzi.mission_mate.feature.login.loginNavGraph
+import com.goalpanzi.mission_mate.feature.onboarding.boardSetupNavGraph
+import com.goalpanzi.mission_mate.feature.onboarding.invitationCodeNavGraph
+import com.goalpanzi.mission_mate.feature.onboarding.onboardingNavGraph
@Composable
internal fun MainNavHost(
@@ -28,6 +31,13 @@ internal fun MainNavHost(
loginNavGraph(
onBackClick = { navigator.popBackStack() }
)
+ onboardingNavGraph(
+ onClickBoardSetup = { },
+ onClickInvitationCode = { },
+ onClickSetting = { }
+ )
+ boardSetupNavGraph()
+ invitationCodeNavGraph()
}
}
}
\ No newline at end of file
diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt
index 20f8eaaf..7e4ca198 100644
--- a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt
+++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt
@@ -6,6 +6,9 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.goalpanzi.mission_mate.core.navigation.RouteModel
import com.goalpanzi.mission_mate.feature.login.navigateToLogin
+import com.goalpanzi.mission_mate.feature.onboarding.navigateToBoardSetup
+import com.goalpanzi.mission_mate.feature.onboarding.navigateToInvitationCode
+import com.goalpanzi.mission_mate.feature.onboarding.navigateToOnboarding
class MainNavigator(
val navController: NavHostController
@@ -21,6 +24,18 @@ class MainNavigator(
fun navigateToLogin() {
navController.navigateToLogin()
}
+
+ fun navigationToOnboarding() {
+ navController.navigateToOnboarding()
+ }
+
+ fun navigationToBoardSetup() {
+ navController.navigateToBoardSetup()
+ }
+
+ fun navigationToInvitationCode() {
+ navController.navigateToInvitationCode()
+ }
}
@Composable
diff --git a/feature/onboarding/.gitignore b/feature/onboarding/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/feature/onboarding/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/onboarding/build.gradle.kts b/feature/onboarding/build.gradle.kts
new file mode 100644
index 00000000..9e30fb5f
--- /dev/null
+++ b/feature/onboarding/build.gradle.kts
@@ -0,0 +1,70 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.jetbrains.kotlin.android)
+ alias(libs.plugins.compose.compiler)
+ alias(libs.plugins.kotlin.ksp)
+ alias(libs.plugins.hilt.android)
+}
+
+android {
+ namespace = "com.goalpanzi.mission_mate.feature.onboarding"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 26
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlin {
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+ composeCompiler {
+ enableStrongSkippingMode = true
+ }
+}
+
+dependencies {
+
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.bundles.lifecycle)
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.bundles.compose)
+ implementation(libs.bundles.coroutines)
+
+ testImplementation(libs.bundles.test)
+ androidTestImplementation(libs.bundles.android.test)
+ androidTestImplementation(platform(libs.androidx.compose.bom))
+ debugImplementation(libs.androidx.ui.tooling)
+ debugImplementation(libs.androidx.ui.test.manifest)
+
+ implementation(libs.androidx.hilt.navigation.compose)
+ implementation(libs.hilt.android)
+ ksp(libs.hilt.compiler)
+
+ implementation(libs.coil.compose)
+
+ implementation(project(":core:designsystem"))
+ implementation(project(":core:navigation"))
+}
\ No newline at end of file
diff --git a/feature/onboarding/consumer-rules.pro b/feature/onboarding/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/feature/onboarding/proguard-rules.pro b/feature/onboarding/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/feature/onboarding/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/onboarding/src/androidTest/java/com/goalpanzi/mission_mate/feature/onboarding/ExampleInstrumentedTest.kt b/feature/onboarding/src/androidTest/java/com/goalpanzi/mission_mate/feature/onboarding/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..4e1b6ca9
--- /dev/null
+++ b/feature/onboarding/src/androidTest/java/com/goalpanzi/mission_mate/feature/onboarding/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.goalpanzi.mission_mate.feature.onboarding
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.goalpanzi.mission_mate.feature.onboarding.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/feature/onboarding/src/main/AndroidManifest.xml b/feature/onboarding/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/feature/onboarding/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/OnboardingNavigation.kt b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/OnboardingNavigation.kt
new file mode 100644
index 00000000..6d29deb4
--- /dev/null
+++ b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/OnboardingNavigation.kt
@@ -0,0 +1,45 @@
+package com.goalpanzi.mission_mate.feature.onboarding
+
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.compose.composable
+import com.goalpanzi.mission_mate.core.navigation.OnboardingRouteModel
+import com.goalpanzi.mission_mate.core.navigation.RouteModel
+
+fun NavController.navigateToOnboarding() {
+ this.navigate(RouteModel.Onboarding)
+}
+
+fun NavController.navigateToBoardSetup() {
+ this.navigate(OnboardingRouteModel.BoardSetup)
+}
+
+fun NavController.navigateToInvitationCode() {
+ this.navigate(OnboardingRouteModel.InvitationCode)
+}
+
+fun NavGraphBuilder.onboardingNavGraph(
+ onClickBoardSetup : () -> Unit,
+ onClickInvitationCode : () -> Unit,
+ onClickSetting : () -> Unit
+) {
+ composable {
+ OnboardingRoute(
+ onClickBoardSetup = onClickBoardSetup,
+ onClickInvitationCode = onClickInvitationCode,
+ onClickSetting = onClickSetting
+ )
+ }
+}
+
+fun NavGraphBuilder.boardSetupNavGraph() {
+ composable {
+
+ }
+}
+
+fun NavGraphBuilder.invitationCodeNavGraph() {
+ composable {
+
+ }
+}
\ No newline at end of file
diff --git a/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/OnboardingScreen.kt b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/OnboardingScreen.kt
new file mode 100644
index 00000000..a1e430a9
--- /dev/null
+++ b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/OnboardingScreen.kt
@@ -0,0 +1,138 @@
+package com.goalpanzi.mission_mate.feature.onboarding
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+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.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.goalpanzi.mission_mate.core.designsystem.theme.ColorGray1_FF404249
+import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF
+import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography
+import com.goalpanzi.mission_mate.feature.onboarding.component.OnboardingNavigationButton
+import com.goalpanzi.mission_mate.feature.onboarding.component.OutlinedTextBox
+import com.goalpanzi.mission_mate.feature.onboarding.component.StableImage
+import com.goalpanzi.mission_mate.core.designsystem.R as designSystemResource
+
+@Composable
+fun OnboardingRoute(
+ modifier: Modifier = Modifier,
+ onClickBoardSetup : () -> Unit,
+ onClickInvitationCode : () -> Unit,
+ onClickSetting : () -> Unit
+) {
+ OnboardingScreen(
+ modifier = modifier.fillMaxSize(),
+ onClickBoardSetup = onClickBoardSetup,
+ onClickInvitationCode = onClickInvitationCode,
+ onClickSetting = onClickSetting
+ )
+}
+
+@Composable
+fun OnboardingScreen(
+ modifier: Modifier = Modifier,
+ onClickBoardSetup : () -> Unit,
+ onClickInvitationCode : () -> Unit,
+ onClickSetting : () -> Unit
+) {
+ Box(
+ modifier = modifier.background(ColorWhite_FFFFFFFF)
+ ) {
+ Image(
+ modifier = Modifier
+ .fillMaxWidth()
+ .wrapContentHeight(),
+ painter = painterResource(id = designSystemResource.drawable.background_jeju),
+ contentDescription = null,
+ contentScale = ContentScale.FillWidth
+ )
+ Column(
+ modifier = modifier,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ IconButton(
+ modifier = Modifier
+ .padding(end = 10.dp, top = 24.dp)
+ .align(Alignment.End),
+ onClick = onClickSetting
+ ) {
+ Icon(
+ painter = painterResource(id = designSystemResource.drawable.ic_setting),
+ contentDescription = null
+ )
+ }
+ Text(
+ modifier = Modifier.padding(bottom = 52.dp),
+ text = stringResource(id = R.string.onboarding_ready_title),
+ textAlign = TextAlign.Center,
+ style = MissionMateTypography.heading_sm_regular,
+ color = ColorGray1_FF404249
+ )
+ OutlinedTextBox(
+ text = stringResource(id = R.string.onboarding_level_1),
+ modifier = Modifier.padding(bottom = 23.dp)
+ )
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 7.dp)
+ .wrapContentHeight(),
+ contentAlignment = Alignment.BottomCenter
+ ) {
+ StableImage(
+ modifier = Modifier
+ .fillMaxWidth()
+ .wrapContentHeight(),
+ drawableResId = designSystemResource.drawable.background_jeju_theme,
+ contentScale = ContentScale.FillWidth
+ )
+ StableImage(
+ modifier = Modifier
+ .fillMaxWidth(0.564f)
+ .wrapContentHeight(),
+ drawableResId = designSystemResource.drawable.img_rabbit_selected,
+ contentScale = ContentScale.FillWidth
+ )
+ }
+ Row(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(horizontal = 24.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(18.dp)
+ ) {
+ OnboardingNavigationButton(
+ modifier = Modifier.weight(1f),
+ titleId = R.string.onboarding_crating_board_title,
+ descriptionId = R.string.onboarding_crating_board_desription,
+ imageId = designSystemResource.drawable.ic_creating_board,
+ onClick = onClickBoardSetup
+ )
+ OnboardingNavigationButton(
+ modifier = Modifier.weight(1f),
+ titleId = R.string.onboarding_code_title,
+ descriptionId = R.string.onboarding_code_desription,
+ imageId = designSystemResource.drawable.ic_invitation_friend,
+ onClick = onClickInvitationCode
+ )
+ }
+ }
+ }
+
+}
diff --git a/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/OnboardingNavigationButton.kt b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/OnboardingNavigationButton.kt
new file mode 100644
index 00000000..f69f73a6
--- /dev/null
+++ b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/OnboardingNavigationButton.kt
@@ -0,0 +1,67 @@
+package com.goalpanzi.mission_mate.feature.onboarding.component
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ElevatedButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.goalpanzi.mission_mate.core.designsystem.ext.dropShadow
+import com.goalpanzi.mission_mate.core.designsystem.theme.ColorGray1_FF404249
+import com.goalpanzi.mission_mate.core.designsystem.theme.ColorGray3_FF727484
+import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF
+import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography
+
+@Composable
+fun OnboardingNavigationButton(
+ @StringRes titleId : Int,
+ @StringRes descriptionId : Int,
+ @DrawableRes imageId: Int,
+ onClick : () -> Unit,
+ modifier: Modifier = Modifier,
+ shape: Shape = RoundedCornerShape(20.dp)
+){
+ ElevatedButton(
+ modifier = modifier.dropShadow(shape),
+ onClick = onClick,
+ shape = shape,
+ colors = ButtonDefaults.elevatedButtonColors(
+ containerColor = ColorWhite_FFFFFFFF
+ ),
+ contentPadding = PaddingValues()
+ ) {
+ Column(
+ modifier = Modifier,
+ verticalArrangement = Arrangement.spacedBy(6.dp)
+ ) {
+ Text(
+ modifier = Modifier.padding(start = 20.dp, end = 20.dp,top = 20.dp),
+ text = stringResource(id = titleId),
+ style = MissionMateTypography.title_xl_bold,
+ color = ColorGray1_FF404249
+ )
+ Text(
+ modifier = Modifier.padding(start = 20.dp, end = 20.dp, bottom = 12.dp),
+ text = stringResource(id = descriptionId),
+ style = MissionMateTypography.body_lg_regular,
+ color = ColorGray3_FF727484
+ )
+ StableImage(
+ modifier = Modifier
+ .padding(bottom = 12.dp, end = 8.dp)
+ .align(Alignment.End),
+ drawableResId = imageId
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/OutlinedBox.kt b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/OutlinedBox.kt
new file mode 100644
index 00000000..528c5198
--- /dev/null
+++ b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/OutlinedBox.kt
@@ -0,0 +1,44 @@
+package com.goalpanzi.mission_mate.feature.onboarding.component
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.dp
+import com.goalpanzi.mission_mate.core.designsystem.theme.ColorOrange_FFFF5732
+import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography
+
+@Composable
+fun OutlinedTextBox(
+ text : String,
+ modifier: Modifier = Modifier,
+ borderStroke: BorderStroke = BorderStroke(1.dp, ColorOrange_FFFF5732),
+ shape: Shape = RoundedCornerShape(50),
+ contentPadding : PaddingValues = PaddingValues(vertical = 1.dp, horizontal = 14.dp),
+ textStyle: TextStyle = MissionMateTypography.title_lg_regular,
+ textColor : Color = ColorOrange_FFFF5732
+){
+ Box(
+ modifier = modifier
+ .border(borderStroke, shape)
+ .padding(contentPadding),
+ contentAlignment = Alignment.Center
+ ){
+ Text(
+ text = text,
+ style = textStyle,
+ color = textColor
+ )
+ }
+}
\ No newline at end of file
diff --git a/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/StableImage.kt b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/StableImage.kt
new file mode 100644
index 00000000..7f657642
--- /dev/null
+++ b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/component/StableImage.kt
@@ -0,0 +1,24 @@
+package com.goalpanzi.mission_mate.feature.onboarding.component
+
+import androidx.annotation.DrawableRes
+import androidx.compose.foundation.Image
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+
+@Composable
+fun StableImage (
+ @DrawableRes drawableResId: Int,
+ modifier: Modifier = Modifier,
+ contentScale: ContentScale = ContentScale.Fit,
+ description : String? = null,
+) {
+ val painter = painterResource(id = drawableResId)
+ Image(
+ modifier = modifier,
+ painter = painter,
+ contentScale = contentScale,
+ contentDescription = description
+ )
+}
\ No newline at end of file
diff --git a/feature/onboarding/src/main/res/values/strings.xml b/feature/onboarding/src/main/res/values/strings.xml
new file mode 100644
index 00000000..0392472e
--- /dev/null
+++ b/feature/onboarding/src/main/res/values/strings.xml
@@ -0,0 +1,10 @@
+
+
+ 미션 완수를 위해\n경쟁할 준비가 되었나요?
+ 미션보드\n생성하기
+ 내 목표는 내가~
+ 초대코드\n입력하기
+ 초대받고 왔지~
+
+ LV1. 제주도
+
\ No newline at end of file
diff --git a/feature/onboarding/src/test/java/com/goalpanzi/mission_mate/feature/onboarding/ExampleUnitTest.kt b/feature/onboarding/src/test/java/com/goalpanzi/mission_mate/feature/onboarding/ExampleUnitTest.kt
new file mode 100644
index 00000000..9bab1c85
--- /dev/null
+++ b/feature/onboarding/src/test/java/com/goalpanzi/mission_mate/feature/onboarding/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.goalpanzi.mission_mate.feature.onboarding
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index dc40b48a..e4bbee1f 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -108,6 +108,7 @@ credentials-auth = { group = "androidx.credentials", name = "credentials-play-se
google-id = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version = "identity" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+
[plugins]
## Android gradle plugin
android-application = { id = "com.android.application", version.ref = "agp" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index c5bf1a21..a6c442f9 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -31,3 +31,4 @@ include(":feature:login")
include(":feature:main")
include(":feature:board")
include(":core:model")
+include(":feature:onboarding")