Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8f63862
refactor: PrezelTheme 기본 텍스트 스타일 및 색상 설정
moondev03 Jan 22, 2026
2d4f27d
fix: Light 테마의 `borderSmall` 색상 값 수정
moondev03 Jan 22, 2026
4c4d49b
feat: 디자인 시스템 PrezelButton 컴포넌트 추가
moondev03 Jan 22, 2026
219021c
feat: 아이콘 리소스 추상화 `IconSource` 도입
moondev03 Jan 22, 2026
84da40b
feat: `PrezelButton` 스타일 및 구성 요소 정의
moondev03 Jan 22, 2026
813507b
refactor: PrezelButton 컴포넌트 구조 개선 및 유연성 확보
moondev03 Jan 22, 2026
ade9670
refactor: `PrezelButtonStyle`에 `@Immutable` 추가
moondev03 Jan 22, 2026
391cc38
feat: 버튼 프리뷰를 위한 유틸리티 컴포넌트 추가
moondev03 Jan 22, 2026
b2b10cb
refactor: `PrezelButton` 미리보기 코드 단순화 및 재구성
moondev03 Jan 22, 2026
0a3370c
feat: PrezelTextButton 공통 컴포넌트 추가
moondev03 Jan 22, 2026
03b3194
refactor: `PrezelButton` 아이콘 버튼 스타일 및 패딩 로직 개선
moondev03 Jan 22, 2026
ba49636
refactor: `PrezelButton` 아이콘-텍스트 간 간격 및 아이콘 전용 패딩 로직 개선
moondev03 Jan 22, 2026
fa702ae
feat: `PrezelIconButton` 공통 컴포넌트 추가
moondev03 Jan 22, 2026
3d429d6
style: Detekt `DestructuringDeclarationWithTooManyEntries` 규칙 비활성화
moondev03 Jan 22, 2026
012053f
refactor: `PrezelButton` 컴포넌트 로직 개선
moondev03 Jan 22, 2026
9cb5601
refactor: `PrezelIconButton`의 아이콘 파라미터 타입 변경
moondev03 Jan 22, 2026
8ecbd75
refactor: 버튼 프리뷰 레이아웃 구조 개선
moondev03 Jan 22, 2026
fa429c4
refactor: IconSource 인터페이스에 contentDescription 추가
moondev03 Jan 22, 2026
4ecb9c4
style: detekt-config.yml 포맷팅 수정
moondev03 Jan 22, 2026
dffe880
refactor: `PrezelTopAppBar` 프리뷰 코드 개선
moondev03 Jan 22, 2026
11d093d
refactor: PrezelButton에서 불필요한 InteractionSource 제거
moondev03 Jan 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.team.prezel.core.designsystem.component

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
Expand All @@ -8,6 +9,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
Expand All @@ -19,7 +21,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles
import com.team.prezel.core.designsystem.icon.PrezelIcons
import com.team.prezel.core.designsystem.preview.ThemePreview
import com.team.prezel.core.designsystem.theme.PrezelTheme
Expand Down Expand Up @@ -63,14 +64,9 @@ private fun prezelTopAppBarColors() =
@Composable
private fun PrezelTopAppBarTitleOnlyPreview() {
PrezelTheme {
PrezelTopAppBar(
title = {
Text(
text = "제목",
style = PrezelTextStyles.Body2Bold.toTextStyle(),
)
},
)
Surface(color = PrezelTheme.colors.bgRegular) {
PrezelTopAppBar(title = { Text(text = "제목") })
}
}
}

Expand All @@ -79,23 +75,19 @@ private fun PrezelTopAppBarTitleOnlyPreview() {
@Composable
private fun PrezelTopAppBarWithLeadingPreview() {
PrezelTheme {
PrezelTopAppBar(
title = {
Text(
text = "제목",
style = PrezelTextStyles.Body2Bold.toTextStyle(),
)
},
leadingIcon = {
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "뒤로가기",
tint = PrezelTheme.colors.iconRegular,
)
}
},
)
Surface(color = PrezelTheme.colors.bgRegular) {
PrezelTopAppBar(
title = { Text(text = "제목") },
leadingIcon = {
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "뒤로가기",
)
}
},
)
}
}
}

Expand All @@ -104,39 +96,33 @@ private fun PrezelTopAppBarWithLeadingPreview() {
@Composable
private fun PrezelTopAppBarWithAllIconsPreview() {
PrezelTheme {
PrezelTopAppBar(
title = {
Text(
text = "제목",
style = PrezelTextStyles.Body2Bold.toTextStyle(),
)
},
leadingIcon = {
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "뒤로가기",
tint = PrezelTheme.colors.iconRegular,
)
}
},
trailingIcons = {
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "검색",
tint = PrezelTheme.colors.iconRegular,
)
}
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "더보기",
tint = PrezelTheme.colors.iconRegular,
)
}
},
)
Surface(color = PrezelTheme.colors.bgRegular) {
PrezelTopAppBar(
title = { Text(text = "제목") },
leadingIcon = {
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "뒤로가기",
)
}
},
trailingIcons = {
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "검색",
)
}
IconButton(onClick = {}) {
Icon(
painter = painterResource(PrezelIcons.Blank),
contentDescription = "더보기",
)
}
},
)
}
}
}

Expand All @@ -149,6 +135,7 @@ private fun PrezelTopAppBarScrollTestPreview() {

Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
containerColor = PrezelTheme.colors.bgRegular,
topBar = {
PrezelTopAppBar(
title = { Text("제목") },
Expand All @@ -165,14 +152,12 @@ private fun PrezelTopAppBarScrollTestPreview() {
},
) { innerPadding ->
LazyColumn(
modifier = Modifier.padding(innerPadding),
modifier = Modifier
.padding(innerPadding)
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
items(30) { index ->
Text(
text = "Item $index",
modifier = Modifier.padding(16.dp),
)
}
items(30) { index -> Text(text = "Item $index") }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.team.prezel.core.designsystem.component.button

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import com.team.prezel.core.designsystem.icon.DrawableIcon
import com.team.prezel.core.designsystem.icon.IconSource
import com.team.prezel.core.designsystem.icon.PrezelIcons
import com.team.prezel.core.designsystem.preview.ThemePreview
import com.team.prezel.core.designsystem.theme.PrezelTheme

@Composable
fun PrezelButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
text: String? = null,
icon: IconSource? = null,
enabled: Boolean = true,
style: PrezelButtonStyle = PrezelButtonStyle(),
) {
val hasText = text != null
val hasIcon = icon != null
require(hasText || hasIcon) { "Button은 text 또는 icon 중 하나는 반드시 필요합니다." }
val (buttonType, buttonHierarchy, buttonSize, isRounded) = style

Surface(
onClick = onClick,
modifier = modifier.semantics { role = Role.Button },
enabled = enabled,
shape = prezelButtonShape(isRounded = isRounded),
color = prezelButtonContainerColor(type = buttonType, hierarchy = buttonHierarchy, enabled = enabled),
border = prezelButtonBorderStroke(type = buttonType, hierarchy = buttonHierarchy, enabled = enabled),
) {
CompositionLocalProvider(
LocalTextStyle provides prezelButtonTextStyle(buttonSize),
LocalContentColor provides prezelButtonContentColor(type = buttonType, hierarchy = buttonHierarchy, enabled = enabled),
) {
Row(
modifier = Modifier.padding(prezelButtonContentPadding(size = buttonSize, onlyIcon = hasIcon && !hasText)),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
PrezelButtonIcon(icon = icon, size = buttonSize)

if (!hasText) return@Row
if (hasIcon) {
val spacing = if (buttonSize == PrezelButtonSize.REGULAR) PrezelTheme.spacing.V8 else PrezelTheme.spacing.V4
Comment thread
moondev03 marked this conversation as resolved.
Spacer(modifier = Modifier.width(width = spacing))
}

Text(text = text)
}
Comment thread
moondev03 marked this conversation as resolved.
}
}
}

@ThemePreview
@Composable
private fun PrezelButtonPreviewFilled() {
PrezelTheme {
PrezelButtonPreviewByType(type = PrezelButtonType.FILLED, content = ::PrezelButtonPreviewItem)
}
}

@ThemePreview
@Composable
private fun PrezelButtonPreviewOutlined() {
PrezelTheme {
PrezelButtonPreviewByType(type = PrezelButtonType.OUTLINED, content = ::PrezelButtonPreviewItem)
}
}

@ThemePreview
@Composable
private fun PrezelButtonPreviewGhost() {
PrezelTheme {
PrezelButtonPreviewByType(type = PrezelButtonType.GHOST, content = ::PrezelButtonPreviewItem)
}
}

@Composable
private fun PrezelButtonPreviewItem(
style: PrezelButtonStyle,
enabled: Boolean,
) {
PrezelButton(
text = "Label",
icon = DrawableIcon(resId = PrezelIcons.Blank),
onClick = {},
enabled = enabled,
style = style,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.team.prezel.core.designsystem.component.button

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.team.prezel.core.designsystem.preview.PreviewScaffold
import com.team.prezel.core.designsystem.theme.PrezelTheme
import kotlinx.collections.immutable.persistentListOf

internal typealias PrezelButtonPreviewContent = @Composable (PrezelButtonStyle, Boolean) -> Unit

@Immutable
private data class PreviewVariant(
val enabled: Boolean,
val isRounded: Boolean,
)

private val PreviewVariants = persistentListOf(
PreviewVariant(enabled = true, isRounded = false),
PreviewVariant(enabled = true, isRounded = true),
PreviewVariant(enabled = false, isRounded = true),
PreviewVariant(enabled = false, isRounded = false),
)

private val PreviewSizes = persistentListOf(
PrezelButtonSize.XSMALL,
PrezelButtonSize.SMALL,
PrezelButtonSize.REGULAR,
)

@Composable
internal fun PrezelButtonPreviewByType(
type: PrezelButtonType,
content: PrezelButtonPreviewContent,
) {
PreviewScaffold {
Text(text = type.name, style = PrezelTheme.typography.title2Medium)

PreviewVariants.forEach { variant ->
HorizontalDivider()
PrezelButtonVariantSection(
type = type,
enabled = variant.enabled,
isRounded = variant.isRounded,
content = content,
)
}
}
}

@Composable
private fun PrezelButtonVariantSection(
type: PrezelButtonType,
enabled: Boolean,
isRounded: Boolean,
content: PrezelButtonPreviewContent,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(text = "Hierarchy: Primary | Enabled: $enabled | Radius: $isRounded", style = PrezelTheme.typography.body3Medium)
PrezelButtonPreviewHierarchyBlock(
type = type,
hierarchy = PrezelButtonHierarchy.PRIMARY,
enabled = enabled,
isRounded = isRounded,
content = content,
)
Text(text = "Hierarchy: Secondary | Enabled: $enabled | Radius: $isRounded", style = PrezelTheme.typography.body3Medium)
PrezelButtonPreviewHierarchyBlock(
type = type,
hierarchy = PrezelButtonHierarchy.SECONDARY,
enabled = enabled,
isRounded = isRounded,
content = content,
)
}
}

@Composable
private fun PrezelButtonPreviewHierarchyBlock(
type: PrezelButtonType,
hierarchy: PrezelButtonHierarchy,
enabled: Boolean,
isRounded: Boolean,
content: PrezelButtonPreviewContent,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
PreviewSizes.forEach { size ->
content(
PrezelButtonStyle(
buttonType = type,
buttonHierarchy = hierarchy,
buttonSize = size,
isRounded = isRounded,
),
enabled,
)
}
}
}
Loading