diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColors.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt similarity index 97% rename from Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColors.kt rename to Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt index 638536b..ff34f93 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColors.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt @@ -1,4 +1,4 @@ -package com.team.prezel.core.designsystem.theme +package com.team.prezel.core.designsystem.foundation.color import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.Color diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelFontFamily.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelFontFamily.kt new file mode 100644 index 0000000..29b5f65 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelFontFamily.kt @@ -0,0 +1,11 @@ +package com.team.prezel.core.designsystem.foundation.typography + +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import com.team.prezel.core.designsystem.R + +internal val SuitFamily = FontFamily( + Font(R.font.suit_medium, PrezelFontWeight.REGULAR.value), + Font(R.font.suit_semi_bold, PrezelFontWeight.MEDIUM.value), + Font(R.font.suit_bold, PrezelFontWeight.BOLD.value), +) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelFontSpec.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelFontSpec.kt new file mode 100644 index 0000000..1405115 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelFontSpec.kt @@ -0,0 +1,58 @@ +package com.team.prezel.core.designsystem.foundation.typography + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em + +enum class PrezelFontWeight( + val value: FontWeight, +) { + REGULAR(FontWeight.Medium), + MEDIUM(FontWeight.SemiBold), + BOLD(FontWeight.Bold), +} + +enum class PrezelFontSize( + private val value: Dp, +) { + V100(12.dp), + V200(14.dp), + V300(16.dp), + V400(20.dp), + V500(24.dp), + ; + + val sp: TextUnit + @Composable + get() = with(LocalDensity.current) { value.toSp() } +} + +enum class PrezelFontLineHeight( + val value: Dp, +) { + V100(16.dp), + V150(18.dp), + V200(20.dp), + V300(24.dp), + V400(28.dp), + V500(32.dp), + ; + + val sp: TextUnit + @Composable + get() = with(LocalDensity.current) { value.toSp() } +} + +enum class PrezelFontLetterSpacing( + val value: TextUnit, +) { + V100(0.012.em), + V200(0.008.em), + V300(0.006.em), + V400((-0.012).em), + V500((-0.018).em), +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTextStyle.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTextStyle.kt new file mode 100644 index 0000000..a9a6ad5 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTextStyle.kt @@ -0,0 +1,21 @@ +package com.team.prezel.core.designsystem.foundation.typography + +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle + +data class PrezelTextStyle( + val fontWeight: PrezelFontWeight, + val fontSize: PrezelFontSize, + val lineHeight: PrezelFontLineHeight, + val letterSpacing: PrezelFontLetterSpacing, +) { + @Composable + fun toTextStyle(): TextStyle = + TextStyle( + fontFamily = SuitFamily, + fontWeight = fontWeight.value, + fontSize = fontSize.sp, + lineHeight = lineHeight.sp, + letterSpacing = letterSpacing.value, + ) +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTextStyles.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTextStyles.kt new file mode 100644 index 0000000..a0ad794 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTextStyles.kt @@ -0,0 +1,122 @@ +package com.team.prezel.core.designsystem.foundation.typography + +internal object PrezelTextStyles { + val Title1Medium: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.MEDIUM, + fontSize = PrezelFontSize.V500, + lineHeight = PrezelFontLineHeight.V500, + letterSpacing = PrezelFontLetterSpacing.V500, + ) + + val Title1Bold: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.BOLD, + fontSize = PrezelFontSize.V500, + lineHeight = PrezelFontLineHeight.V500, + letterSpacing = PrezelFontLetterSpacing.V500, + ) + + val Title2Medium: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.MEDIUM, + fontSize = PrezelFontSize.V400, + lineHeight = PrezelFontLineHeight.V400, + letterSpacing = PrezelFontLetterSpacing.V400, + ) + + val Title2Bold: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.BOLD, + fontSize = PrezelFontSize.V400, + lineHeight = PrezelFontLineHeight.V400, + letterSpacing = PrezelFontLetterSpacing.V400, + ) + + val Body1Regular: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.REGULAR, + fontSize = PrezelFontSize.V400, + lineHeight = PrezelFontLineHeight.V400, + letterSpacing = PrezelFontLetterSpacing.V300, + ) + + val Body1Medium: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.MEDIUM, + fontSize = PrezelFontSize.V400, + lineHeight = PrezelFontLineHeight.V400, + letterSpacing = PrezelFontLetterSpacing.V300, + ) + + val Body1Bold: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.BOLD, + fontSize = PrezelFontSize.V400, + lineHeight = PrezelFontLineHeight.V400, + letterSpacing = PrezelFontLetterSpacing.V300, + ) + + val Body2Regular: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.REGULAR, + fontSize = PrezelFontSize.V300, + lineHeight = PrezelFontLineHeight.V300, + letterSpacing = PrezelFontLetterSpacing.V300, + ) + + val Body2Medium: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.MEDIUM, + fontSize = PrezelFontSize.V300, + lineHeight = PrezelFontLineHeight.V300, + letterSpacing = PrezelFontLetterSpacing.V300, + ) + + val Body2Bold: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.BOLD, + fontSize = PrezelFontSize.V300, + lineHeight = PrezelFontLineHeight.V300, + letterSpacing = PrezelFontLetterSpacing.V300, + ) + + val Body3Regular: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.REGULAR, + fontSize = PrezelFontSize.V200, + lineHeight = PrezelFontLineHeight.V200, + letterSpacing = PrezelFontLetterSpacing.V200, + ) + + val Body3Medium: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.MEDIUM, + fontSize = PrezelFontSize.V200, + lineHeight = PrezelFontLineHeight.V200, + letterSpacing = PrezelFontLetterSpacing.V200, + ) + + val Body3Bold: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.BOLD, + fontSize = PrezelFontSize.V200, + lineHeight = PrezelFontLineHeight.V200, + letterSpacing = PrezelFontLetterSpacing.V200, + ) + + val Caption1Regular: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.REGULAR, + fontSize = PrezelFontSize.V200, + lineHeight = PrezelFontLineHeight.V150, + letterSpacing = PrezelFontLetterSpacing.V200, + ) + + val Caption1Medium: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.MEDIUM, + fontSize = PrezelFontSize.V200, + lineHeight = PrezelFontLineHeight.V150, + letterSpacing = PrezelFontLetterSpacing.V200, + ) + + val Caption2Regular: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.REGULAR, + fontSize = PrezelFontSize.V100, + lineHeight = PrezelFontLineHeight.V100, + letterSpacing = PrezelFontLetterSpacing.V100, + ) + + val Caption2Medium: PrezelTextStyle = PrezelTextStyle( + fontWeight = PrezelFontWeight.MEDIUM, + fontSize = PrezelFontSize.V100, + lineHeight = PrezelFontLineHeight.V100, + letterSpacing = PrezelFontLetterSpacing.V100, + ) +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTypography.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTypography.kt new file mode 100644 index 0000000..613668f --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/PrezelTypography.kt @@ -0,0 +1,31 @@ +package com.team.prezel.core.designsystem.foundation.typography + +import androidx.compose.runtime.Immutable +import androidx.compose.ui.text.TextStyle + +@Immutable +data class PrezelTypography( + // Title + // 페이지나 섹션의 주요 제목 등 핵심 정보를 강조하는 데 사용하는 스타일입니다. + val title1Medium: TextStyle, + val title1Bold: TextStyle, + val title2Medium: TextStyle, + val title2Bold: TextStyle, + // Body + // 일반 본문과 설명, 단일 문장 또는 단락 등의 주된 콘텐츠 전달에 사용하는 스타일입니다. + val body1Regular: TextStyle, + val body1Medium: TextStyle, + val body1Bold: TextStyle, + val body2Regular: TextStyle, + val body2Medium: TextStyle, + val body2Bold: TextStyle, + val body3Regular: TextStyle, + val body3Medium: TextStyle, + val body3Bold: TextStyle, + // Caption + // 부가 정보, 안내, 설명, 작성 시간 등 메인 콘텐츠를 보조하는 짧은 정보를 전달할 때 사용하는 스타일입니다. + val caption1Regular: TextStyle, + val caption1Medium: TextStyle, + val caption2Regular: TextStyle, + val caption2Medium: TextStyle, +) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/TypeTokens.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/TypeTokens.kt deleted file mode 100644 index 6bad659..0000000 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/typography/TypeTokens.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.team.prezel.core.designsystem.foundation.typography - -import androidx.compose.material3.Typography -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.sp - -// Set of Material typography styles to start with -val Typography = Typography( - bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp, - ), - /* Other default text styles to override - titleLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - labelSmall = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Medium, - fontSize = 11.sp, - lineHeight = 16.sp, - letterSpacing = 0.5.sp - ) - */ -) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt index fcc2c44..a3c7f1d 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.team.prezel.core.designsystem.foundation.color.ColorTokens +import com.team.prezel.core.designsystem.foundation.color.PrezelColors import com.team.prezel.core.designsystem.preview.ThemePreview import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTheme.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTheme.kt index 68a3a31..fe88872 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTheme.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTheme.kt @@ -5,14 +5,22 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.staticCompositionLocalOf +import com.team.prezel.core.designsystem.foundation.color.PrezelColors +import com.team.prezel.core.designsystem.foundation.typography.PrezelTypography private val LocalPrezelColors = staticCompositionLocalOf { error("No PrezelColors provided") } +private val LocalPrezelTypography = staticCompositionLocalOf { error("No PrezelTypography provided") } object PrezelTheme { val colors: PrezelColors @Composable @ReadOnlyComposable get() = LocalPrezelColors.current + + val typography: PrezelTypography + @Composable + @ReadOnlyComposable + get() = LocalPrezelTypography.current } @Composable @@ -21,9 +29,11 @@ fun PrezelTheme( content: @Composable () -> Unit, ) { val colorScheme = if (isDarkTheme) PrezelColorScheme.Dark else PrezelColorScheme.Light + val typographyScheme = PrezelTypographyScheme.Default() CompositionLocalProvider( LocalPrezelColors provides colorScheme, + LocalPrezelTypography provides typographyScheme, content = content, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTypographyScheme.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTypographyScheme.kt new file mode 100644 index 0000000..6beef84 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTypographyScheme.kt @@ -0,0 +1,169 @@ +package com.team.prezel.core.designsystem.theme + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.isSpecified +import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles +import com.team.prezel.core.designsystem.foundation.typography.PrezelTypography +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +internal object PrezelTypographyScheme { + @Composable + fun Default() = + PrezelTypography( + title1Medium = PrezelTextStyles.Title1Medium.toTextStyle(), + title1Bold = PrezelTextStyles.Title1Bold.toTextStyle(), + title2Medium = PrezelTextStyles.Title2Medium.toTextStyle(), + title2Bold = PrezelTextStyles.Title2Bold.toTextStyle(), + body1Regular = PrezelTextStyles.Body1Regular.toTextStyle(), + body1Medium = PrezelTextStyles.Body1Medium.toTextStyle(), + body1Bold = PrezelTextStyles.Body1Bold.toTextStyle(), + body2Regular = PrezelTextStyles.Body2Regular.toTextStyle(), + body2Medium = PrezelTextStyles.Body2Medium.toTextStyle(), + body2Bold = PrezelTextStyles.Body2Bold.toTextStyle(), + body3Regular = PrezelTextStyles.Body3Regular.toTextStyle(), + body3Medium = PrezelTextStyles.Body3Medium.toTextStyle(), + body3Bold = PrezelTextStyles.Body3Bold.toTextStyle(), + caption1Regular = PrezelTextStyles.Caption1Regular.toTextStyle(), + caption1Medium = PrezelTextStyles.Caption1Medium.toTextStyle(), + caption2Regular = PrezelTextStyles.Caption2Regular.toTextStyle(), + caption2Medium = PrezelTextStyles.Caption2Medium.toTextStyle(), + ) +} + +@Preview( + showBackground = true, + device = "spec:width=800dp,height=1900dp", + fontScale = 10f, +) +@Composable +private fun PrezelTypographySchemePreview() { + PrezelTheme { + PrezelTypographyPreviewContent() + } +} + +@Composable +private fun PrezelTypographyPreviewContent( + typography: PrezelTypography = PrezelTheme.typography, + items: ImmutableList> = persistentListOf( + Triple("Title", "Title1 Medium", typography.title1Medium), + Triple("Title", "Title1 Bold", typography.title1Bold), + Triple("Title", "Title2 Medium", typography.title2Medium), + Triple("Title", "Title2 Bold", typography.title2Bold), + Triple("Body", "Body1 Regular", typography.body1Regular), + Triple("Body", "Body1 Medium", typography.body1Medium), + Triple("Body", "Body1 Bold", typography.body1Bold), + Triple("Body", "Body2 Regular", typography.body2Regular), + Triple("Body", "Body2 Medium", typography.body2Medium), + Triple("Body", "Body2 Bold", typography.body2Bold), + Triple("Body", "Body3 Regular", typography.body3Regular), + Triple("Body", "Body3 Medium", typography.body3Medium), + Triple("Body", "Body3 Bold", typography.body3Bold), + Triple("Caption", "Caption1 Regular", typography.caption1Regular), + Triple("Caption", "Caption1 Medium", typography.caption1Medium), + Triple("Caption", "Caption2 Regular", typography.caption2Regular), + Triple("Caption", "Caption2 Medium", typography.caption2Medium), + ), +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(PrezelTheme.colors.bgRegular) + .verticalScroll(rememberScrollState()) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + items + .groupBy { it.first } + .forEach { (group, groupedItems) -> + HorizontalDivider() + Text(text = group, style = typography.title1Bold) + HorizontalDivider() + + Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + groupedItems.forEach { item -> + TypographyRow(name = item.second, style = item.third) + } + } + } + } +} + +@Composable +private fun TypographyRow( + name: String, + style: TextStyle, +) { + Column( + modifier = Modifier + .fillMaxSize() + .background( + color = PrezelTheme.colors.bgRegular, + shape = RoundedCornerShape(12.dp), + ), + verticalArrangement = Arrangement.spacedBy(6.dp), + ) { + Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { + val fontSize = style.fontSize + val lineHeight = style.lineHeight + val letterSpacing = style.letterSpacing + val fontWeight = style.fontWeight + + Text( + text = buildString { + append("$name (") + append("size: $fontSize") + if (lineHeight.isSpecified) append(" · lh: $lineHeight") + if (letterSpacing.isSpecified) append(" · ls: $letterSpacing") + if (fontWeight != null) append(" · w: ${fontWeight.weight}") + append(")") + }, + style = PrezelTheme.typography.body3Bold, + color = PrezelTheme.colors.textMedium, + ) + } + + TypographySampleText(style = style) + } +} + +@Composable +private fun TypographySampleText( + style: TextStyle, + sampleKo: String = "이 문장은 글꼴의 형태와 가독성을 확인하기 위한 예시입니다.", + sampleEn: String = "This sentence is an example for checking font shape and readability.", +) { + Column( + modifier = Modifier + .background( + color = PrezelTheme.colors.bgLarge, + shape = RoundedCornerShape(12.dp), + ).padding(8.dp), + ) { + Text( + text = sampleKo, + style = style, + color = PrezelTheme.colors.textLarge, + ) + Text( + text = sampleEn, + style = style, + color = PrezelTheme.colors.textLarge, + ) + } +} diff --git a/Prezel/core/designsystem/src/main/res/font/suit_bold.otf b/Prezel/core/designsystem/src/main/res/font/suit_bold.otf new file mode 100644 index 0000000..7c6bab9 Binary files /dev/null and b/Prezel/core/designsystem/src/main/res/font/suit_bold.otf differ diff --git a/Prezel/core/designsystem/src/main/res/font/suit_medium.otf b/Prezel/core/designsystem/src/main/res/font/suit_medium.otf new file mode 100644 index 0000000..5d97ac5 Binary files /dev/null and b/Prezel/core/designsystem/src/main/res/font/suit_medium.otf differ diff --git a/Prezel/core/designsystem/src/main/res/font/suit_semi_bold.otf b/Prezel/core/designsystem/src/main/res/font/suit_semi_bold.otf new file mode 100644 index 0000000..9769761 Binary files /dev/null and b/Prezel/core/designsystem/src/main/res/font/suit_semi_bold.otf differ