feat: align native UI with Happy Engineering style

This commit is contained in:
Hermes Agent
2026-07-09 11:27:01 +00:00
parent d8eb84c219
commit 68a1884ea5
@@ -46,9 +46,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ChatBubble
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Folder
import androidx.compose.material.icons.filled.Key
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Save
@@ -58,9 +56,6 @@ import androidx.compose.material.icons.filled.Wifi
import androidx.compose.material.icons.filled.WifiOff
import androidx.compose.material.icons.outlined.Article
import androidx.compose.material.icons.outlined.Bolt
import androidx.compose.material.icons.outlined.Diamond
import androidx.compose.material.icons.outlined.LocalFireDepartment
import androidx.compose.material.icons.outlined.EmojiEvents
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
@@ -110,11 +105,11 @@ import java.net.URLEncoder
import java.util.concurrent.TimeUnit
enum class Screen(val label: String, val icon: ImageVector, val title: String, val kicker: String) {
Quest("Quest", Icons.Filled.ChatBubble, "Quest", "Hermes training path"),
Files("Files", Icons.Filled.Folder, "Backpack", "Workspace loot"),
Terminal("Terminal", Icons.Filled.Terminal, "Power move", "Run a command"),
Status("Status", Icons.Outlined.EmojiEvents, "League", "Companion stats"),
Settings("Settings", Icons.Filled.Settings, "Nest", "Connection setup")
Quest("Chat", Icons.Filled.ChatBubble, "Agent", "Claude Code mobile client"),
Files("Files", Icons.Filled.Folder, "Workspace", "Project files"),
Terminal("Terminal", Icons.Filled.Terminal, "Terminal", "Run commands"),
Status("Status", Icons.Outlined.Bolt, "Sessions", "Companion status"),
Settings("Settings", Icons.Filled.Settings, "Settings", "Pair companion")
}
data class FileEntry(val name: String, val path: String, val type: String, val size: Long)
@@ -247,8 +242,8 @@ fun HermesNativeApp() {
colorScheme = darkColorScheme(
background = Cream,
surface = Paper,
primary = Green,
onPrimary = Color.White,
primary = Teal,
onPrimary = Color.Black,
onBackground = Ink,
onSurface = Ink
)
@@ -317,25 +312,23 @@ fun NativeTopBar(screen: Screen, online: Boolean) {
.padding(horizontal = 16.dp, vertical = 10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) {
RaisedCircle(color = Green, shadow = GreenDark, content = "")
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
RaisedCircle(color = Purple, shadow = PurpleDark, content = "H")
Column(Modifier.weight(1f)) {
TinyLabel(screen.kicker)
Text(screen.title, fontSize = 31.sp, fontWeight = FontWeight.Black, color = Ink, lineHeight = 31.sp)
Text(screen.title, fontSize = 30.sp, fontWeight = FontWeight.Black, color = Ink, lineHeight = 31.sp)
}
StatChip(Icons.Outlined.LocalFireDepartment, "7", Orange)
StatChip(Icons.Outlined.Diamond, "550", Blue)
StatChip(Icons.Filled.Favorite, "3", Red)
StatusDot(online)
}
RaisedCard(
color = if (online) PaleGreen else PaleOrange,
shadow = if (online) GreenShadow else OrangeShadow,
border = if (online) GreenBorder else OrangeBorder,
color = if (online) TealPanel else WarningPanel,
shadow = PanelShadow,
border = if (online) TealBorder else WarningBorder,
modifier = Modifier.fillMaxWidth()
) {
Row(Modifier.padding(12.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Icon(if (online) Icons.Filled.Wifi else Icons.Filled.WifiOff, contentDescription = null, tint = if (online) GreenDark else Orange)
Text(if (online) "Companion online — ready for quests" else "Companion offline — check Settings", color = if (online) GreenDark else Orange, fontWeight = FontWeight.Black)
Icon(if (online) Icons.Filled.Wifi else Icons.Filled.WifiOff, contentDescription = null, tint = if (online) Teal else Orange)
Text(if (online) "Companion connected" else "Set companion URL and access key", color = if (online) Teal else Orange, fontWeight = FontWeight.Black)
}
}
}
@@ -359,9 +352,9 @@ fun NativeBottomBar(current: Screen, onSelect: (Screen) -> Unit) {
icon = { Icon(item.icon, contentDescription = item.label) },
label = { Text(item.label, fontWeight = FontWeight.Black, fontSize = 11.sp) },
colors = NavigationBarItemDefaults.colors(
selectedIconColor = GreenDark,
selectedTextColor = GreenDark,
indicatorColor = PaleGreen,
selectedIconColor = Teal,
selectedTextColor = Teal,
indicatorColor = TealPanel,
unselectedIconColor = Muted,
unselectedTextColor = Muted
)
@@ -380,10 +373,10 @@ fun QuestScreen(api: CompanionApi) {
val messages = remember { mutableStateListOf<ChatMessage>() }
ScreenList {
HeroCard(icon = Icons.Filled.ChatBubble, title = "Give Hermes one clean mission.", label = "Daily quest", text = "Short, direct prompts work best. The native app calls the local companion server.")
HeroCard(icon = Icons.Filled.ChatBubble, title = "Claude Code from anywhere.", label = "Agent control", text = "Send prompts to your local Hermes companion and continue work from your phone.")
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
PathPill(Icons.Filled.CheckCircle, "Check", true)
PathPill(Icons.Outlined.Bolt, "Ask", true, current = true)
PathPill(Icons.Filled.CheckCircle, "Connect", true)
PathPill(Icons.Outlined.Bolt, "Prompt", true, current = true)
PathPill(Icons.Filled.ChatBubble, "Review", false)
}
if (messages.isEmpty()) EmptyLesson()
@@ -391,8 +384,8 @@ fun QuestScreen(api: CompanionApi) {
if (error.isNotBlank()) ErrorCard(error)
RaisedCard(Modifier.fillMaxWidth()) {
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(10.dp)) {
AppTextField(value = prompt, onValue = { prompt = it }, placeholder = "What should Hermes do?", minLines = 3)
PrimaryButton(text = if (busy) "Working…" else "Start quest", icon = Icons.Filled.PlayArrow, enabled = !busy && prompt.isNotBlank()) {
AppTextField(value = prompt, onValue = { prompt = it }, placeholder = "Message Hermes", minLines = 3)
PrimaryButton(text = if (busy) "Working…" else "Send", icon = Icons.Filled.PlayArrow, enabled = !busy && prompt.isNotBlank()) {
val p = prompt.trim()
prompt = ""
messages.add(ChatMessage("You", p))
@@ -427,7 +420,7 @@ fun FilesScreen(api: CompanionApi) {
LaunchedEffect(Unit) { load(".") }
ScreenList {
CompactQuest(title = "Workspace files", label = "Backpack", text = "Tap folders to go deeper. Files open in a native editor.", icon = Icons.Filled.Folder) { load() }
CompactQuest(title = "Project files", label = "Workspace", text = "Browse and edit files through the companion server.", icon = Icons.Filled.Folder) { load() }
RaisedCard(Modifier.fillMaxWidth()) {
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
@@ -468,7 +461,7 @@ fun TerminalScreen(api: CompanionApi) {
var busy by remember { mutableStateOf(false) }
ScreenList {
HeroCard(icon = Icons.Filled.Terminal, title = "Run one safe command.", label = "Power move", text = "Commands execute through the companion server inside the configured workspace.", orbColor = Blue, orbShadow = BlueDark)
HeroCard(icon = Icons.Filled.Terminal, title = "Run workspace commands.", label = "Terminal", text = "Execute commands on the paired machine without leaving the app.", orbColor = Purple, orbShadow = PurpleDark)
RaisedCard(Modifier.fillMaxWidth()) {
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(10.dp)) {
FieldLabel("Working directory")
@@ -495,7 +488,7 @@ fun StatusScreen(api: CompanionApi) {
fun refresh() = scope.launch { health = runCatching { api.health() }.getOrElse { HealthState(false, it.message ?: "Health check failed") } }
ScreenList {
CompactQuest(title = "Companion status", label = "League board", text = health.status, icon = Icons.Outlined.EmojiEvents, orbColor = Gold, orbShadow = GoldDark) { refresh() }
CompactQuest(title = "Companion status", label = "Sessions", text = health.status, icon = Icons.Outlined.Bolt, orbColor = Teal, orbShadow = TealDark) { refresh() }
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Metric("Hermes", if (health.hermesCli.startsWith("Found")) "Ready" else "", Modifier.weight(1f))
Metric("Uptime", health.uptime, Modifier.weight(1f))
@@ -522,7 +515,7 @@ fun SettingsScreen(api: CompanionApi) {
var status by remember { mutableStateOf("Paste the companion access key, then test the connection.") }
ScreenList {
CompactQuest(title = "Pair your companion", label = "Nest setup", text = status, icon = Icons.Filled.Settings, orbColor = Green, orbShadow = GreenDark) {}
CompactQuest(title = "Pair companion", label = "Settings", text = status, icon = Icons.Filled.Settings, orbColor = Purple, orbShadow = PurpleDark) {}
RaisedCard(Modifier.fillMaxWidth()) {
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(10.dp)) {
FieldLabel("Companion server URL")
@@ -562,7 +555,7 @@ fun RaisedCard(modifier: Modifier = Modifier, color: Color = Paper, shadow: Colo
}
@Composable
fun HeroCard(icon: ImageVector, title: String, label: String, text: String, orbColor: Color = Green, orbShadow: Color = GreenDark) {
fun HeroCard(icon: ImageVector, title: String, label: String, text: String, orbColor: Color = Teal, orbShadow: Color = TealDark) {
RaisedCard(Modifier.fillMaxWidth()) {
Row(Modifier.padding(16.dp), horizontalArrangement = Arrangement.spacedBy(14.dp), verticalAlignment = Alignment.Top) {
RaisedIcon(icon, orbColor, orbShadow)
@@ -572,7 +565,7 @@ fun HeroCard(icon: ImageVector, title: String, label: String, text: String, orbC
}
@Composable
fun CompactQuest(title: String, label: String, text: String, icon: ImageVector, orbColor: Color = Green, orbShadow: Color = GreenDark, onRefresh: () -> Unit) {
fun CompactQuest(title: String, label: String, text: String, icon: ImageVector, orbColor: Color = Teal, orbShadow: Color = TealDark, onRefresh: () -> Unit) {
RaisedCard(Modifier.fillMaxWidth()) {
Row(Modifier.padding(14.dp), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
RaisedIcon(icon, orbColor, orbShadow, size = 58)
@@ -583,45 +576,46 @@ fun CompactQuest(title: String, label: String, text: String, icon: ImageVector,
}
@Composable fun RaisedIcon(icon: ImageVector, color: Color, shadow: Color, size: Int = 66) { Box(Modifier.size(size.dp), contentAlignment = Alignment.Center) { Box(Modifier.matchParentSize().padding(top = 5.dp).clip(CircleShape).background(shadow)); Box(Modifier.matchParentSize().padding(bottom = 5.dp).clip(CircleShape).background(color), contentAlignment = Alignment.Center) { Icon(icon, null, tint = Color.White, modifier = Modifier.size((size / 2).dp)) } } }
@Composable fun RaisedCircle(color: Color, shadow: Color, content: String) { Box(Modifier.size(54.dp), contentAlignment = Alignment.Center) { Box(Modifier.matchParentSize().padding(top = 5.dp).clip(RoundedCornerShape(18.dp)).background(shadow)); Box(Modifier.matchParentSize().padding(bottom = 5.dp).clip(RoundedCornerShape(18.dp)).background(color), contentAlignment = Alignment.Center) { Text(content, fontSize = 24.sp) } } }
@Composable fun StatChip(icon: ImageVector, value: String, color: Color) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(2.dp), modifier = Modifier.clip(RoundedCornerShape(99.dp)).background(Paper).padding(horizontal = 7.dp, vertical = 3.dp)) { Icon(icon, null, tint = color, modifier = Modifier.size(15.dp)); Text(value, color = color, fontWeight = FontWeight.Black, fontSize = 12.sp) } }
@Composable fun RaisedCircle(color: Color, shadow: Color, content: String) { Box(Modifier.size(54.dp), contentAlignment = Alignment.Center) { Box(Modifier.matchParentSize().padding(top = 5.dp).clip(RoundedCornerShape(18.dp)).background(shadow)); Box(Modifier.matchParentSize().padding(bottom = 5.dp).clip(RoundedCornerShape(18.dp)).background(color), contentAlignment = Alignment.Center) { Text(content, fontSize = 24.sp, fontWeight = FontWeight.Black, color = Color.White) } } }
@Composable fun StatusDot(online: Boolean) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.clip(RoundedCornerShape(99.dp)).background(if (online) TealPanel else WarningPanel).padding(horizontal = 10.dp, vertical = 7.dp)) { Box(Modifier.size(8.dp).clip(CircleShape).background(if (online) Teal else Orange)); Text(if (online) "LIVE" else "SETUP", color = if (online) Teal else Orange, fontWeight = FontWeight.Black, fontSize = 11.sp) } }
@Composable fun TinyLabel(text: String) { Text(text.uppercase(), color = Muted, fontSize = 11.sp, fontWeight = FontWeight.Black, letterSpacing = 0.7.sp) }
@Composable fun FieldLabel(text: String) { Text(text.uppercase(), color = Muted, fontSize = 12.sp, fontWeight = FontWeight.Black) }
@Composable fun PathPill(icon: ImageVector, text: String, done: Boolean, current: Boolean = false) { Row(Modifier.clip(RoundedCornerShape(99.dp)).background(if (current) Green else if (done) PaleGreen else Surface).padding(horizontal = 12.dp, vertical = 10.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(5.dp)) { Icon(icon, null, tint = if (current) Color.White else GreenDark, modifier = Modifier.size(18.dp)); Text(text, color = if (current) Color.White else GreenDark, fontWeight = FontWeight.Black, fontSize = 13.sp) } }
@Composable fun EmptyLesson() { RaisedCard(Modifier.fillMaxWidth()) { Column(Modifier.padding(18.dp), horizontalAlignment = Alignment.CenterHorizontally) { Text("🪽", fontSize = 42.sp); Text("No mission yet", color = Ink, fontWeight = FontWeight.Black, fontSize = 20.sp); Text("Try: check PM2 status or summarize logs.", color = Muted, fontWeight = FontWeight.ExtraBold) } } }
@Composable fun Bubble(msg: ChatMessage) { RaisedCard(Modifier.fillMaxWidth().padding(start = if (msg.role == "You") 28.dp else 0.dp, end = if (msg.role == "You") 0.dp else 28.dp), color = if (msg.role == "You") PaleGreen else PaleGold) { Column(Modifier.padding(12.dp)) { TinyLabel(msg.role); Text(msg.content, color = Ink, fontWeight = FontWeight.ExtraBold, lineHeight = 19.sp) } } }
@Composable fun PathPill(icon: ImageVector, text: String, done: Boolean, current: Boolean = false) { Row(Modifier.clip(RoundedCornerShape(99.dp)).background(if (current) Teal else if (done) TealPanel else Surface).padding(horizontal = 12.dp, vertical = 10.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(5.dp)) { Icon(icon, null, tint = if (current) Color.Black else Teal, modifier = Modifier.size(18.dp)); Text(text, color = if (current) Color.Black else Teal, fontWeight = FontWeight.Black, fontSize = 13.sp) } }
@Composable fun EmptyLesson() { RaisedCard(Modifier.fillMaxWidth()) { Column(Modifier.padding(18.dp), horizontalAlignment = Alignment.CenterHorizontally) { Text("\$ happy", color = Teal, fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace, fontWeight = FontWeight.Black, fontSize = 24.sp); Text("No messages yet", color = Ink, fontWeight = FontWeight.Black, fontSize = 20.sp); Text("Try: check PM2 status or summarize logs.", color = Muted, fontWeight = FontWeight.ExtraBold) } } }
@Composable fun Bubble(msg: ChatMessage) { RaisedCard(Modifier.fillMaxWidth().padding(start = if (msg.role == "You") 28.dp else 0.dp, end = if (msg.role == "You") 0.dp else 28.dp), color = if (msg.role == "You") TealPanel else Surface) { Column(Modifier.padding(12.dp)) { TinyLabel(msg.role); Text(msg.content, color = Ink, fontWeight = FontWeight.ExtraBold, lineHeight = 19.sp) } } }
@Composable fun ErrorCard(text: String) { RaisedCard(Modifier.fillMaxWidth(), color = PaleRed, shadow = RedShadow, border = RedBorder) { Text(text, Modifier.padding(12.dp), color = Red, fontWeight = FontWeight.Black) } }
@Composable fun CodeCard(text: String) { RaisedCard(Modifier.fillMaxWidth()) { Text(text, Modifier.padding(14.dp), color = BlueDark, fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace, fontSize = 13.sp, lineHeight = 18.sp) } }
@Composable fun FileRow(entry: FileEntry, onClick: () -> Unit) { RaisedCard(Modifier.fillMaxWidth()) { Row(Modifier.clickable(onClick = onClick).padding(10.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) { Box(Modifier.size(42.dp).clip(RoundedCornerShape(14.dp)).background(if (entry.type == "directory") PaleBlue else PaleGold), contentAlignment = Alignment.Center) { Icon(if (entry.type == "directory") Icons.Filled.Folder else Icons.Outlined.Article, null, tint = if (entry.type == "directory") Blue else GoldDark) }; Text(entry.name, Modifier.weight(1f), color = Ink, fontWeight = FontWeight.Black, maxLines = 1, overflow = TextOverflow.Ellipsis); Text(if (entry.type == "file") "${entry.size} B" else "dir", color = Muted, fontWeight = FontWeight.Black, fontSize = 12.sp) } } }
@Composable fun Metric(label: String, value: String, modifier: Modifier = Modifier) { RaisedCard(modifier) { Column(Modifier.padding(10.dp), horizontalAlignment = Alignment.CenterHorizontally) { Text(value, color = GreenDark, fontWeight = FontWeight.Black, fontSize = 18.sp, maxLines = 1, overflow = TextOverflow.Ellipsis); Text(label.uppercase(), color = Muted, fontWeight = FontWeight.Black, fontSize = 10.sp) } } }
@Composable fun AppTextField(value: String, onValue: (String) -> Unit, placeholder: String, minLines: Int = 1, keyboardType: KeyboardType = KeyboardType.Text, password: Boolean = false) { OutlinedTextField(value = value, onValueChange = onValue, modifier = Modifier.fillMaxWidth(), placeholder = { Text(placeholder, color = Muted) }, minLines = minLines, keyboardOptions = KeyboardOptions(keyboardType = keyboardType), visualTransformation = if (password) PasswordVisualTransformation() else androidx.compose.ui.text.input.VisualTransformation.None, shape = RoundedCornerShape(16.dp), colors = TextFieldDefaults.colors(focusedContainerColor = Surface, unfocusedContainerColor = Surface, focusedIndicatorColor = Green, unfocusedIndicatorColor = NeutralBorder, cursorColor = GreenDark)) }
@Composable fun PrimaryButton(text: String, icon: ImageVector, modifier: Modifier = Modifier, enabled: Boolean = true, onClick: () -> Unit) { Button(onClick = onClick, enabled = enabled, modifier = modifier.height(54.dp), shape = RoundedCornerShape(16.dp), colors = ButtonDefaults.buttonColors(containerColor = Green, contentColor = Color.White, disabledContainerColor = NeutralBorder), elevation = ButtonDefaults.buttonElevation(defaultElevation = 6.dp, pressedElevation = 1.dp)) { Text(text, fontWeight = FontWeight.Black); Spacer(Modifier.width(6.dp)); Icon(icon, null) } }
@Composable fun Metric(label: String, value: String, modifier: Modifier = Modifier) { RaisedCard(modifier) { Column(Modifier.padding(10.dp), horizontalAlignment = Alignment.CenterHorizontally) { Text(value, color = Teal, fontWeight = FontWeight.Black, fontSize = 18.sp, maxLines = 1, overflow = TextOverflow.Ellipsis); Text(label.uppercase(), color = Muted, fontWeight = FontWeight.Black, fontSize = 10.sp) } } }
@Composable fun AppTextField(value: String, onValue: (String) -> Unit, placeholder: String, minLines: Int = 1, keyboardType: KeyboardType = KeyboardType.Text, password: Boolean = false) { OutlinedTextField(value = value, onValueChange = onValue, modifier = Modifier.fillMaxWidth(), placeholder = { Text(placeholder, color = Muted) }, minLines = minLines, keyboardOptions = KeyboardOptions(keyboardType = keyboardType), visualTransformation = if (password) PasswordVisualTransformation() else androidx.compose.ui.text.input.VisualTransformation.None, shape = RoundedCornerShape(16.dp), colors = TextFieldDefaults.colors(focusedContainerColor = Surface, unfocusedContainerColor = Surface, focusedIndicatorColor = Teal, unfocusedIndicatorColor = NeutralBorder, cursorColor = Teal)) }
@Composable fun PrimaryButton(text: String, icon: ImageVector, modifier: Modifier = Modifier, enabled: Boolean = true, onClick: () -> Unit) { Button(onClick = onClick, enabled = enabled, modifier = modifier.height(54.dp), shape = RoundedCornerShape(16.dp), colors = ButtonDefaults.buttonColors(containerColor = Teal, contentColor = Color.Black, disabledContainerColor = NeutralBorder), elevation = ButtonDefaults.buttonElevation(defaultElevation = 6.dp, pressedElevation = 1.dp)) { Text(text, fontWeight = FontWeight.Black); Spacer(Modifier.width(6.dp)); Icon(icon, null) } }
@Composable fun SecondaryButton(text: String, icon: ImageVector, modifier: Modifier = Modifier, onClick: () -> Unit) { Button(onClick = onClick, modifier = modifier.height(54.dp), shape = RoundedCornerShape(16.dp), colors = ButtonDefaults.buttonColors(containerColor = Surface, contentColor = Ink), elevation = ButtonDefaults.buttonElevation(defaultElevation = 4.dp, pressedElevation = 1.dp)) { Text(text, fontWeight = FontWeight.Black); Spacer(Modifier.width(6.dp)); Icon(icon, null) } }
@Composable fun RoundButton(icon: ImageVector, onClick: () -> Unit) { Button(onClick = onClick, modifier = Modifier.size(50.dp), shape = RoundedCornerShape(16.dp), contentPadding = androidx.compose.foundation.layout.PaddingValues(0.dp), colors = ButtonDefaults.buttonColors(containerColor = Blue, contentColor = Color.White), elevation = ButtonDefaults.buttonElevation(defaultElevation = 5.dp, pressedElevation = 1.dp)) { Icon(icon, null) } }
@Composable fun RoundButton(icon: ImageVector, onClick: () -> Unit) { Button(onClick = onClick, modifier = Modifier.size(50.dp), shape = RoundedCornerShape(16.dp), contentPadding = androidx.compose.foundation.layout.PaddingValues(0.dp), colors = ButtonDefaults.buttonColors(containerColor = Purple, contentColor = Color.White), elevation = ButtonDefaults.buttonElevation(defaultElevation = 5.dp, pressedElevation = 1.dp)) { Icon(icon, null) } }
val Green = Color(0xFF58CC02)
val GreenDark = Color(0xFF7FE83B)
val GreenShadow = Color(0xFF244B19)
val GreenBorder = Color(0xFF3D7F28)
val PaleGreen = Color(0xFF17301A)
val Blue = Color(0xFF1CB0F6)
val BlueDark = Color(0xFF73D4FF)
val PaleBlue = Color(0xFF112A3A)
val Gold = Color(0xFFFFC800)
val GoldDark = Color(0xFFFFD95A)
val PaleGold = Color(0xFF332A10)
val Orange = Color(0xFFFFA033)
val PaleOrange = Color(0xFF332312)
val OrangeBorder = Color(0xFF7B4D1C)
val OrangeShadow = Color(0xFF26180C)
val Red = Color(0xFFFF6B6B)
val PaleRed = Color(0xFF3A171B)
val RedBorder = Color(0xFF8B3D45)
val RedShadow = Color(0xFF271013)
val Cream = Color(0xFF08100E)
val Paper = Color(0xFF111B18)
val Surface = Color(0xFF17231F)
val Ink = Color(0xFFEAF7EE)
val Muted = Color(0xFF9FB4A7)
val NeutralBorder = Color(0xFF294138)
val NeutralShadow = Color(0xFF060B0A)
val Teal = Color(0xFF28DBC9)
val TealDark = Color(0xFF0F8F84)
val TealPanel = Color(0xFF0E2B2A)
val TealBorder = Color(0xFF176C66)
val Purple = Color(0xFF6701E6)
val PurpleDark = Color(0xFF3B0087)
val PurplePanel = Color(0xFF211133)
val Blue = Color(0xFF3B82F6)
val BlueDark = Color(0xFF8AB7FF)
val PaleBlue = Color(0xFF111B2B)
val GoldDark = Color(0xFFFBBF24)
val PaleGold = Color(0xFF211B10)
val Orange = Color(0xFFFBBF24)
val WarningPanel = Color(0xFF2B2111)
val WarningBorder = Color(0xFF7A5A1B)
val Red = Color(0xFFF87171)
val PaleRed = Color(0xFF311719)
val RedBorder = Color(0xFF7A363A)
val RedShadow = Color(0xFF0A0304)
val Cream = Color(0xFF000000)
val Paper = Color(0xFF0B0F12)
val Surface = Color(0xFF12181D)
val Ink = Color(0xFFF4F4F5)
val Muted = Color(0xFF9CA3AF)
val NeutralBorder = Color(0xFF2A3138)
val NeutralShadow = Color(0xFF030506)
val PanelShadow = Color(0xFF040707)