feat: redesign ReasoningBlock + SourceCards to match design system
ReasoningBlock: accent-tinted background + gradient border (matches pill language), KaizenShapes.md (16dp radius), larger padding, better line height (20sp), softer icon tint. Replaces flat gray box with solid border. SourceCards: gradient border instead of solid, KaizenShapes.md, shows domain instead of full URL in the link line, slightly larger padding. Both blocks now use the same visual language as the rest of the app — gradient borders, accent tinting, squircle shapes.
This commit is contained in:
parent
b2df7e9330
commit
421b29ef5a
1 changed files with 37 additions and 22 deletions
|
|
@ -28,6 +28,7 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
|
@ -49,44 +50,51 @@ fun ReasoningBlock(reasoning: String, streaming: Boolean = false) {
|
|||
val accent = LocalKaizenAccent.current
|
||||
var expanded by remember { mutableStateOf(streaming) }
|
||||
|
||||
val bg = if (isDark) Color.White.copy(alpha = 0.05f) else Color.Black.copy(alpha = 0.03f)
|
||||
val borderColor = if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.06f)
|
||||
val bg = accent.primary.copy(alpha = if (isDark) 0.06f else 0.04f)
|
||||
val borderBrush = remember(isDark, accent) {
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
accent.primary.copy(alpha = if (isDark) 0.20f else 0.15f),
|
||||
accent.primary.copy(alpha = if (isDark) 0.05f else 0.03f),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(KaizenShapes.sm)
|
||||
.clip(KaizenShapes.md)
|
||||
.background(bg)
|
||||
.border(1.dp, borderColor, KaizenShapes.sm)
|
||||
.border(0.8.dp, borderBrush, KaizenShapes.md)
|
||||
) {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { expanded = !expanded }
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
.padding(horizontal = 14.dp, vertical = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(KaizenIcons.Brain, null, tint = accent.primary, modifier = Modifier.size(16.dp))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Icon(KaizenIcons.Brain, null, tint = accent.primary.copy(alpha = 0.75f), modifier = Modifier.size(17.dp))
|
||||
Spacer(Modifier.width(9.dp))
|
||||
Text(
|
||||
stringResource(R.string.stream_reasoning),
|
||||
color = cs.onSurfaceVariant,
|
||||
color = cs.onSurfaceVariant.copy(alpha = 0.75f),
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Icon(
|
||||
if (expanded) KaizenIcons.ChevronUp else KaizenIcons.ChevronDown,
|
||||
null, tint = cs.onSurfaceVariant, modifier = Modifier.size(16.dp),
|
||||
null, tint = cs.onSurfaceVariant.copy(alpha = 0.40f), modifier = Modifier.size(15.dp),
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(expanded, enter = expandVertically(), exit = shrinkVertically()) {
|
||||
Text(
|
||||
reasoning,
|
||||
color = cs.onSurfaceVariant.copy(alpha = 0.8f),
|
||||
color = cs.onSurfaceVariant.copy(alpha = 0.70f),
|
||||
fontSize = 13.sp,
|
||||
lineHeight = 18.sp,
|
||||
modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 10.dp),
|
||||
lineHeight = 20.sp,
|
||||
modifier = Modifier.padding(start = 14.dp, end = 14.dp, bottom = 12.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -175,18 +183,18 @@ fun SourcesBlock(sources: List<SearchSource>, query: String = "") {
|
|||
.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(KaizenIcons.Globe, null, tint = cs.onSurfaceVariant.copy(alpha = 0.6f), modifier = Modifier.size(13.dp))
|
||||
Icon(KaizenIcons.Globe, null, tint = cs.onSurfaceVariant.copy(alpha = 0.55f), modifier = Modifier.size(14.dp))
|
||||
Spacer(Modifier.width(6.dp))
|
||||
Text(
|
||||
stringResource(R.string.stream_sources) + " (${sources.size})",
|
||||
color = cs.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
color = cs.onSurfaceVariant.copy(alpha = 0.55f),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Icon(
|
||||
if (expanded) KaizenIcons.ChevronUp else KaizenIcons.ChevronDown,
|
||||
null, tint = cs.onSurfaceVariant.copy(alpha = 0.4f), modifier = Modifier.size(12.dp),
|
||||
null, tint = cs.onSurfaceVariant.copy(alpha = 0.35f), modifier = Modifier.size(13.dp),
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(expanded, enter = expandVertically(), exit = shrinkVertically()) {
|
||||
|
|
@ -208,7 +216,14 @@ fun SourcesBlock(sources: List<SearchSource>, query: String = "") {
|
|||
private fun SourceCard(source: SearchSource, isDark: Boolean, accent: dev.kaizen.app.ui.theme.themes.KaizenAccentScheme, onClick: () -> Unit) {
|
||||
val cs = MaterialTheme.colorScheme
|
||||
val bg = if (isDark) Color.White.copy(alpha = 0.05f) else Color.Black.copy(alpha = 0.03f)
|
||||
val borderColor = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.05f)
|
||||
val borderBrush = remember(isDark) {
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
if (isDark) Color.White.copy(alpha = 0.10f) else Color.Black.copy(alpha = 0.06f),
|
||||
if (isDark) Color.White.copy(alpha = 0.03f) else Color.Black.copy(alpha = 0.02f),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val domain = remember(source.url) {
|
||||
try {
|
||||
|
|
@ -219,11 +234,11 @@ private fun SourceCard(source: SearchSource, isDark: Boolean, accent: dev.kaizen
|
|||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(KaizenShapes.sm)
|
||||
.clip(KaizenShapes.md)
|
||||
.background(bg)
|
||||
.border(1.dp, borderColor, KaizenShapes.sm)
|
||||
.border(0.8.dp, borderBrush, KaizenShapes.md)
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 12.dp, vertical = 10.dp),
|
||||
.padding(horizontal = 14.dp, vertical = 10.dp),
|
||||
) {
|
||||
Text(
|
||||
source.title.ifEmpty { domain },
|
||||
|
|
@ -235,8 +250,8 @@ private fun SourceCard(source: SearchSource, isDark: Boolean, accent: dev.kaizen
|
|||
)
|
||||
Spacer(Modifier.height(2.dp))
|
||||
Text(
|
||||
source.url,
|
||||
color = accent.primary.copy(alpha = 0.7f),
|
||||
domain,
|
||||
color = accent.primary.copy(alpha = 0.65f),
|
||||
fontSize = 11.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
|
|
@ -245,7 +260,7 @@ private fun SourceCard(source: SearchSource, isDark: Boolean, accent: dev.kaizen
|
|||
Spacer(Modifier.height(3.dp))
|
||||
Text(
|
||||
source.snippet,
|
||||
color = cs.onSurfaceVariant.copy(alpha = 0.5f),
|
||||
color = cs.onSurfaceVariant.copy(alpha = 0.50f),
|
||||
fontSize = 11.sp,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
|
|
|
|||
Loading…
Reference in a new issue