1package com.peachpasswords.ui.components23import androidx.compose.foundation.layout.Box4import androidx.compose.foundation.layout.size5import androidx.compose.foundation.shape.RoundedCornerShape6import androidx.compose.material3.Text7import androidx.compose.runtime.Composable8import androidx.compose.ui.Alignment9import androidx.compose.ui.Modifier10import androidx.compose.ui.draw.clip11import androidx.compose.ui.graphics.Color12import androidx.compose.ui.draw.drawBehind13import androidx.compose.ui.text.font.FontWeight14import androidx.compose.ui.unit.Dp15import androidx.compose.ui.unit.dp16import androidx.compose.ui.unit.em17import androidx.compose.ui.unit.sp18import com.peachpasswords.ui.theme.peachColors19import com.peachpasswords.ui.theme.PeachType20212223242526@Composable27fun FaviconInitials(28 source: String,29 modifier: Modifier = Modifier,30 size: Dp = 26.dp,31 cornerRadius: Dp = (size.value * 0.23f).dp,32) {33 val bg = titleBackground(source)34 Box(35 modifier = modifier36 .size(size)37 .clip(RoundedCornerShape(cornerRadius))38 .drawBehind { drawRect(bg) },39 contentAlignment = Alignment.Center,40 ) {41 Text(42 text = titleInitials(source),43 color = peachColors.T0.copy(alpha = 0.92f),44 fontFamily = PeachType.Mono,45 fontWeight = FontWeight.SemiBold,46 letterSpacing = 0.04.em,47 fontSize = (size.value * 0.34f).sp,48 )49 }50}5152fun titleInitials(source: String): String {53 val cleaned = source.replace(Regex("^https?://"), "").removePrefix("www.").trim()54 if (cleaned.isEmpty()) return "·"55 val words = cleaned.split(Regex("[\\s.\\-_/]+")).filter { it.isNotEmpty() }56 if (words.size >= 2 && words[0].isNotEmpty() && words[1].isNotEmpty()) {57 return (words[0][0].toString() + words[1][0].toString()).uppercase()58 }59 val single = words.firstOrNull() ?: cleaned60 return single.take(2).uppercase()61}626364fun titleBackground(source: String): Color {65 var hash = 066 for (ch in source) hash = ((hash shl 5) - hash + ch.code)67 val hue = (((hash % 360) + 360) % 360).toFloat()68 return hsl(hue, 0.32f, 0.26f)69}7071private fun hsl(h: Float, s: Float, l: Float): Color {72 val c = (1f - kotlin.math.abs(2 * l - 1f)) * s73 val x = c * (1f - kotlin.math.abs((h / 60f) % 2f - 1f))74 val m = l - c / 2f75 val (r, g, b) = when {76 h < 60 -> Triple(c, x, 0f)77 h < 120 -> Triple(x, c, 0f)78 h < 180 -> Triple(0f, c, x)79 h < 240 -> Triple(0f, x, c)80 h < 300 -> Triple(x, 0f, c)81 else -> Triple(c, 0f, x)82 }83 return Color(r + m, g + m, b + m)84}