Skip to content

Instantly share code, notes, and snippets.

@minoism
Created July 14, 2025 14:43
Show Gist options
  • Select an option

  • Save minoism/73f7105a59bbdd54017b9e90523e4d9e to your computer and use it in GitHub Desktop.

Select an option

Save minoism/73f7105a59bbdd54017b9e90523e4d9e to your computer and use it in GitHub Desktop.
package ai.claude.example
import androidx.annotation.FloatRange
import androidx.compose.foundation.Canvas
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathOperation
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
/**
* Puzzle-style card component with gradient background and notch clipping
*
* @param modifier [Modifier]
* @param leftGradientColors Left gradient color list
* @param rightGradientColors Right gradient color list
* @param leftSectionRatio Ratio of left section width
* @param cornerRadius Corner radius
* @param notchRadius Notch radius
*/
@Composable
fun PuzzleCard(
modifier: Modifier = Modifier,
leftGradientColors: List<Color> = listOf(
Color(0xFF4DD0B2),
Color(0xFF6EEFCF)
),
rightGradientColors: List<Color> = listOf(
Color(0xFFB2F5EA),
Color(0xFFE6FFFA)
),
@FloatRange(from = 0.0, to = 1.0)
leftSectionRatio: Float = 0.4f,
cornerRadius: Dp = 12.dp,
notchRadius: Dp = 10.dp
) {
Canvas(modifier = modifier.fillMaxSize()) {
val width = size.width
val height = size.height
val cornerRadiusPx = cornerRadius.toPx()
val notchRadiusPx = notchRadius.toPx()
// Create clipping path
val clipPath = Path().apply {
// Background with rounded corners
addRoundRect(
RoundRect(
rect = Rect(0f, 0f, width, height),
radiusX = cornerRadiusPx,
radiusY = cornerRadiusPx
)
)
// Top-notch
val topNotchPath = Path().apply {
addOval(
Rect(
// Centered at the division line
offset = Offset(width * leftSectionRatio - notchRadiusPx, -notchRadiusPx),
size = Size(notchRadiusPx * 2, notchRadiusPx * 2)
)
)
}
// Bottom-notch
val bottomNotchPath = Path().apply {
addOval(
Rect(
offset = Offset(width * leftSectionRatio - notchRadiusPx, height - notchRadiusPx),
size = Size(notchRadiusPx * 2, notchRadiusPx * 2)
)
)
}
// Subtract notches
op(this, topNotchPath, PathOperation.Difference)
op(this, bottomNotchPath, PathOperation.Difference)
}
// Draw with clipping path
clipPath(clipPath) {
val divisionX = width * leftSectionRatio
// Draw left gradient
drawRect(
brush = Brush.horizontalGradient(
colors = leftGradientColors,
startX = 0f,
// Extend slightly past division to avoid gap
endX = divisionX + 1f
),
topLeft = Offset.Zero,
size = Size(divisionX + 1f, height)
)
// Draw right gradient
drawRect(
brush = Brush.horizontalGradient(
colors = rightGradientColors,
startX = divisionX,
endX = width
),
topLeft = Offset(divisionX, 0f),
size = Size(width - divisionX, height)
)
}
}
}
object PuzzleCardColors {
val CyanGradient = listOf(
Color(0xFFB2F5EA),
Color(0xFFE6FFFA)
)
val BlueGradient = listOf(
Color(0xFF90CDF4),
Color(0xFFBAE6FD)
)
val PurpleGradient = listOf(
Color(0xFFC084FC),
Color(0xFFE9D5FF)
)
}
@Composable
fun PuzzleCardExample() = Column(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding()
.background(Color(0xFF2C2D31))
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
PuzzleCard(
modifier = Modifier
.fillMaxWidth()
.height(120.dp)
)
PuzzleCard(
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
leftGradientColors = PuzzleCardColors.CyanGradient,
rightGradientColors = listOf(
Color(0xFFE0F7FA),
Color(0xFFF0FEFF)
),
leftSectionRatio = 0.35f
)
PuzzleCard(
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
leftGradientColors = PuzzleCardColors.BlueGradient,
rightGradientColors = listOf(
Color(0xFFDBEAFE),
Color(0xFFF0F9FF)
),
leftSectionRatio = 0.3f
)
PuzzleCard(
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
leftGradientColors = PuzzleCardColors.PurpleGradient,
rightGradientColors = listOf(
Color(0xFFF3E8FF),
Color(0xFFFAF5FF)
),
leftSectionRatio = 0.6f,
cornerRadius = 14.dp,
notchRadius = 14.dp
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment