Files
amethyst/.claude/skills/compose-expert/references/shared-composables-catalog.md
T
2025-12-30 15:45:02 +02:00

7.1 KiB

Shared Composables Catalog

This catalog documents shared UI components in commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/.

Directory Structure

commons/src/commonMain/kotlin/.../commons/ui/
├── components/    # Reusable UI components
├── screens/       # Screen-level composables
├── theme/         # Theming and styling
└── feed/          # Feed-specific components

Components (ui/components/)

State Visualization

LoadingState - Centered loading indicator with message

@Composable
fun LoadingState(message: String, modifier: Modifier = Modifier)
  • Use for: Async operations, data fetching
  • Pattern: fillMaxSize, centered Column, CircularProgressIndicator
  • Works on: Android, Desktop

EmptyState - Centered empty state with optional refresh

@Composable
fun EmptyState(
    title: String,
    modifier: Modifier = Modifier,
    description: String? = null,
    onRefresh: (() -> Unit)? = null,
    refreshLabel: String = "Refresh"
)
  • Use for: Empty lists, no data scenarios
  • Pattern: Centered Column, optional OutlinedButton
  • Works on: Android, Desktop

ErrorState - Centered error message with retry

@Composable
fun ErrorState(
    message: String,
    modifier: Modifier = Modifier,
    onRetry: (() -> Unit)? = null,
    retryLabel: String = "Try Again"
)
  • Use for: Error handling, failed operations
  • Pattern: error color, optional Button
  • Works on: Android, Desktop

Feed-Specific States

FeedEmptyState - Pre-configured empty state for feeds

@Composable
fun FeedEmptyState(
    modifier: Modifier = Modifier,
    title: String = "Feed is empty",
    onRefresh: (() -> Unit)? = null
)

FeedErrorState - Pre-configured error state for feeds

@Composable
fun FeedErrorState(
    errorMessage: String,
    modifier: Modifier = Modifier,
    onRetry: (() -> Unit)? = null
)

Action Buttons

Shared Constants:

val ActionButtonShape = RoundedCornerShape(20.dp)
val ActionButtonPadding = PaddingValues(vertical = 0.dp, horizontal = 16.dp)

AddButton - Consistent "Add" action button

@Composable
fun AddButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    text: String = "Add",
    enabled: Boolean = true
)
  • Pattern: OutlinedButton with consistent shape/padding
  • Works on: Android, Desktop

RemoveButton - Consistent "Remove" action button

@Composable
fun RemoveButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    text: String = "Remove",
    enabled: Boolean = true
)

Custom Images

RobohashImage - Deterministic avatar generation

@Composable
fun RobohashImage(
    robot: String,  // Seed (e.g., pubkey)
    modifier: Modifier = Modifier,
    contentDescription: String? = null,
    loadRobohash: Boolean = true
)

// Overload with more options
@Composable
fun RobohashImage(
    robot: String,
    modifier: Modifier = Modifier,
    contentDescription: String? = null,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    colorFilter: ColorFilter? = null,
    loadRobohash: Boolean = true
)
  • Use for: User avatars, deterministic graphics
  • Pattern: Uses CachedRobohash.get(), isLightTheme() detection
  • Fallback: Icons.Default.Face
  • Works on: Android, Desktop (pure ImageVector)

Theme Detection Helper:

@Composable
private fun isLightTheme(): Boolean {
    val background = MaterialTheme.colorScheme.background
    return (background.red + background.green + background.blue) / 3 > 0.5f
}

Feed Components (ui/feed/)

FeedHeader

FeedHeader - Screen header with title and relay status

@Composable
fun FeedHeader(
    title: String,
    connectedRelayCount: Int,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
)
  • Pattern: Row with SpaceBetween, title + RelayStatusIndicator
  • Works on: Android, Desktop

RelayStatusIndicator - Compact relay connection indicator

@Composable
fun RelayStatusIndicator(
    connectedCount: Int,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
)
  • Pattern: Status icon + count text + refresh button
  • Colors: RelayStatusColors.{Disconnected, Connecting, Connected}
  • Visual cues: Check icon (connected), Close icon (disconnected)

Screens (ui/screens/)

Placeholder Pattern

PlaceholderScreen - Generic placeholder

@Composable
fun PlaceholderScreen(
    title: String,
    description: String,
    modifier: Modifier = Modifier
)
  • Pattern: Column with title (headlineMedium) + description
  • Use for: Unimplemented screens, coming soon features

Specific Placeholders:

  • SearchPlaceholder() - Search screen
  • MessagesPlaceholder() - DMs screen
  • NotificationsPlaceholder() - Notifications screen

Pattern: Specific implementations wrap PlaceholderScreen with preset text.

Custom Icons (robohash/parts/)

ImageVector Builder Pattern

Amethyst uses a custom DSL for building ImageVector assets:

@Composable
fun Face0C3po() {
    Image(
        painter = rememberVectorPainter(
            roboBuilder {
                face0C3po(SolidColor(Color.Blue), this)
            }
        ),
        contentDescription = ""
    )
}

fun face0C3po(fgColor: SolidColor, builder: Builder) {
    builder.addPath(pathData1, fill = fgColor, stroke = Black, strokeLineWidth = 1.5f)
    builder.addPath(pathData2, fill = Black, fillAlpha = 0.4f)
    // ...
}

private val pathData1 = PathData {
    moveTo(144.5f, 87.5f)
    reflectiveCurveToRelative(-51.0f, 3.0f, -53.0f, 55.0f)
    // ... path commands
}

roboBuilder - Custom ImageVector.Builder DSL

  • Located in: commons/robohash/
  • Pattern: Builder-based, composable paths
  • Parts: Face, Eyes, Mouth, Body, Accessory (0-9 variants each)
  • Colors: Dynamic (fgColor parameter) + Black constants

CachedRobohash

CachedRobohash.get(seed: String, isLight: Boolean): ImageVector
  • Deterministic: Same seed → same avatar
  • Theme-aware: Different colors for light/dark
  • Cached: Performance optimization
  • Pure ImageVector: Works on all platforms

Sharing Guidelines

Always Share

  • State visualization (Loading, Empty, Error)
  • Action buttons with consistent styling
  • Generic placeholders
  • Custom ImageVector icons
  • Material3 themed components
  • Theme utilities (isLightTheme)

Platform-Specific (Delegate to Experts)

  • Navigation structure (android-expert, desktop-expert)
  • Screen layouts and scaffolds
  • Platform system integrations
  • Gesture handling specifics

Decision Framework

  1. Can it use Material3 primitives? → Share
  2. Does it need platform system APIs? → Platform-specific
  3. Is it a visual component without navigation? → Share
  4. Does it require platform UX patterns? → Ask platform expert

Material3 Usage

All shared composables use Material3:

  • MaterialTheme.colorScheme.* for colors
  • MaterialTheme.typography.* for text styles
  • OutlinedButton, Button, IconButton for actions
  • CircularProgressIndicator for loading
  • Icon, Image for visuals

This ensures consistent theming across Android and Desktop.