From 30a9facf89b48ab0620b886b4ee6c71739d1c355 Mon Sep 17 00:00:00 2001 From: avi Date: Mon, 21 Sep 2026 13:59:02 -0500 Subject: [PATCH] Match reference palette: charcoal page, blue interactive accent, pink-red reserved for recording titles and selected rows --- .../kotlin/com/shonar/desktop/Components.kt | 6 +- .../main/kotlin/com/shonar/desktop/Screens.kt | 12 +++- .../main/kotlin/com/shonar/desktop/Theme.kt | 69 +++++++++++-------- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/app/src/main/kotlin/com/shonar/desktop/Components.kt b/app/src/main/kotlin/com/shonar/desktop/Components.kt index 321cb2b..62579cb 100644 --- a/app/src/main/kotlin/com/shonar/desktop/Components.kt +++ b/app/src/main/kotlin/com/shonar/desktop/Components.kt @@ -82,6 +82,8 @@ fun Modifier.shonarFocus( fun SonarCard( modifier: Modifier = Modifier, onClick: (() -> Unit)? = null, + containerColor: Color = Shonar.Surface, + borderColor: Color = Shonar.Border, content: @Composable () -> Unit, ) { val clickModifier = if (onClick != null) @@ -90,8 +92,8 @@ fun SonarCard( Surface( modifier = modifier.then(clickModifier), shape = Shonar.ShapeCard, - color = Shonar.Surface, - border = BorderStroke(1.dp, Shonar.Border), + color = containerColor, + border = BorderStroke(Shonar.BorderW, borderColor), content = content, ) } diff --git a/app/src/main/kotlin/com/shonar/desktop/Screens.kt b/app/src/main/kotlin/com/shonar/desktop/Screens.kt index ce06b7d..e89e5e6 100644 --- a/app/src/main/kotlin/com/shonar/desktop/Screens.kt +++ b/app/src/main/kotlin/com/shonar/desktop/Screens.kt @@ -409,7 +409,14 @@ fun LibraryScreen(state: DesktopState) { items(entries, key = { it.file.absolutePath }) { e -> val isSelected = e.file.absolutePath in selected SonarCard(Modifier.fillMaxWidth(), - onClick = { state.openDetail(e.file) }) { + onClick = { state.openDetail(e.file) }, + // Selected rows take the reference's muted rose + // wash instead of a plain surface lift. + containerColor = if (isSelected) Shonar.HighlightTint + else Shonar.Surface, + borderColor = if (isSelected) Shonar.Highlight + .copy(alpha = 0.5f) else Shonar.Border, + ) { Row(Modifier.fillMaxWidth().padding(Shonar.CardPadding), verticalAlignment = Alignment.CenterVertically) { Checkbox( @@ -417,8 +424,11 @@ fun LibraryScreen(state: DesktopState) { onCheckedChange = { state.toggleSelected(e.file.absolutePath) }, ) Column(Modifier.weight(1f)) { + // Recording titles carry the reference's + // hot pink highlight; metadata stays gray. Text(e.file.nameWithoutExtension, style = MaterialTheme.typography.titleSmall, + color = Shonar.Highlight, maxLines = 1, overflow = TextOverflow.Ellipsis) Text( diff --git a/app/src/main/kotlin/com/shonar/desktop/Theme.kt b/app/src/main/kotlin/com/shonar/desktop/Theme.kt index 566deea..d8bc1cb 100644 --- a/app/src/main/kotlin/com/shonar/desktop/Theme.kt +++ b/app/src/main/kotlin/com/shonar/desktop/Theme.kt @@ -70,43 +70,52 @@ data class ShonarPalette( val textMuted: Color, val error: Color, val onError: Color, + /** Hot pink-red used to highlight recording entries (titles, + * selected-row wash) — decorative emphasis, not an error color. */ + val highlight: Color = Color(0xFFFB3F7F), + val highlightTint: Color = Color(0x26FB3F7F), ) -/** Near-black neutral charcoal workspace, per the reference: no navy - * cast, one subtle tonal step per surface level, hairline borders a - * few shades above each surface, pink accent used with restraint. */ +/** Charcoal with a faint blue cast, per the reference: page #16181C, + * lifted blue-charcoal cards, hairline borders. Blue owns all + * interactive accent; the reference's hot pink is reserved for + * highlighting recordings (see [ShonarPalette.highlight]). */ private val DarkPalette = ShonarPalette( - background = Color(0xFF141517), // page: neutral near-black - surface = Color(0xFF1B1D21), // cards, fields, pills - surfaceAlt = Color(0xFF101113), // pressed / hover / inset - border = Color(0xFF26282E), // hairline on dark - accent = Color(0xFFF45B87), // pink-magenta: active, primary - accentStrong = Color(0xFFDE4373), // filled-accent hover depth - accentGlow = Color(0x33F45B87), // soft halo (~20% pink) - inkOnAccent = Color(0xFF1F0A13), // text on filled accent - textPrimary = Color(0xFFE6E7EA), - textSecondary = Color(0xFF9A9DA5), - textMuted = Color(0xFF6E7178), - error = Color(0xFFF27272), // red readable on charcoal + background = Color(0xFF16181C), // page: charcoal, blue-cast + surface = Color(0xFF1C2029), // cards, fields, pills + surfaceAlt = Color(0xFF12151C), // pressed / hover / inset + border = Color(0xFF2A2E38), // hairline on dark + accent = Color(0xFF6190E5), // blue: chips, links, progress + accentStrong = Color(0xFF4C6FAD), // filled-accent hover depth + accentGlow = Color(0x336190E5), // soft halo (~20% blue) + inkOnAccent = Color(0xFF0B1526), // text on filled accent + textPrimary = Color(0xFFE6E8EC), + textSecondary = Color(0xFF969CAA), + textMuted = Color(0xFF6B7080), + error = Color(0xFFF85149), // true red, distinct from highlight onError = Color(0xFF1A0B0D), + highlight = Color(0xFFFB3F7F), // hot pink-red: recording titles + highlightTint = Color(0x26FB3F7F), // ~15% pink row wash ) -/** Light mode: warm-neutral paper, same tonal-step hierarchy; the - * accent darkens to a rose that meets AA contrast on white. */ +/** Light mode: neutral-cool paper; blue and pink darken to AA values + * (the highlight pink would be illegible at #FB3F7F on white). */ private val LightPalette = ShonarPalette( - background = Color(0xFFF5F4F6), // page: neutral paper + background = Color(0xFFF4F5F8), // page: cool paper surface = Color(0xFFFFFFFF), // cards, fields, pills - surfaceAlt = Color(0xFFECEBEE), // pressed / hover / inset - border = Color(0xFFDBDADF), // hairline on light - accent = Color(0xFFBE2A5C), // deep rose: readable on paper - accentStrong = Color(0xFF9D1F4B), // filled-accent hover depth - accentGlow = Color(0x26BE2A5C), // soft halo (~15% rose) - inkOnAccent = Color(0xFFFFF5F8), // text on filled accent - textPrimary = Color(0xFF1D1E22), - textSecondary = Color(0xFF5A5C63), - textMuted = Color(0xFF84868D), + surfaceAlt = Color(0xFFE9ECF2), // pressed / hover / inset + border = Color(0xFFD7DBE4), // hairline on light + accent = Color(0xFF0550AE), // deep blue: AA on paper + accentStrong = Color(0xFF0B3E78), // filled-accent hover depth + accentGlow = Color(0x260969DA), // soft halo (~15% blue) + inkOnAccent = Color(0xFFF4F8FF), // text on filled accent + textPrimary = Color(0xFF1C2028), + textSecondary = Color(0xFF585F6C), + textMuted = Color(0xFF828A97), error = Color(0xFFBA1A1A), // AA red on white onError = Color(0xFFFFF8F7), + highlight = Color(0xFFC2185B), // AA rose: recording highlight + highlightTint = Color(0x1AC2185B), // faint rose row wash ) /** Which palette the app renders in. Persisted as "dark" / "light". */ @@ -139,6 +148,10 @@ object Shonar { val BrandTeal = Color(0xFF5EEAD4) val BrandTealDeep = Color(0xFF4FD1C5) + /** Pink-red recording highlight (see [ShonarPalette.highlight]). */ + val Highlight: Color @Composable get() = LocalPalette.current.highlight + val HighlightTint: Color @Composable get() = LocalPalette.current.highlightTint + // ---- shape tokens ---- val RadiusCard = 14.dp // cards + fields val RadiusButton = 12.dp // rectangular buttons @@ -236,7 +249,7 @@ private fun schemeFor(p: ShonarPalette) = if (p === DarkPalette) ShonarDarkScheme else ShonarLightScheme private val ShonarDarkScheme = darkColorScheme( - primary = DarkPalette.accentStrong, + primary = DarkPalette.accent, onPrimary = DarkPalette.inkOnAccent, primaryContainer = DarkPalette.accentGlow, onPrimaryContainer = DarkPalette.accent,