finish skills
This commit is contained in:
@@ -0,0 +1,281 @@
|
||||
# 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
|
||||
```kotlin
|
||||
@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
|
||||
```kotlin
|
||||
@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
|
||||
```kotlin
|
||||
@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
|
||||
```kotlin
|
||||
@Composable
|
||||
fun FeedEmptyState(
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = "Feed is empty",
|
||||
onRefresh: (() -> Unit)? = null
|
||||
)
|
||||
```
|
||||
|
||||
**FeedErrorState** - Pre-configured error state for feeds
|
||||
```kotlin
|
||||
@Composable
|
||||
fun FeedErrorState(
|
||||
errorMessage: String,
|
||||
modifier: Modifier = Modifier,
|
||||
onRetry: (() -> Unit)? = null
|
||||
)
|
||||
```
|
||||
|
||||
### Action Buttons
|
||||
|
||||
**Shared Constants**:
|
||||
```kotlin
|
||||
val ActionButtonShape = RoundedCornerShape(20.dp)
|
||||
val ActionButtonPadding = PaddingValues(vertical = 0.dp, horizontal = 16.dp)
|
||||
```
|
||||
|
||||
**AddButton** - Consistent "Add" action button
|
||||
```kotlin
|
||||
@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
|
||||
```kotlin
|
||||
@Composable
|
||||
fun RemoveButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
text: String = "Remove",
|
||||
enabled: Boolean = true
|
||||
)
|
||||
```
|
||||
|
||||
### Custom Images
|
||||
|
||||
**RobohashImage** - Deterministic avatar generation
|
||||
```kotlin
|
||||
@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**:
|
||||
```kotlin
|
||||
@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
|
||||
```kotlin
|
||||
@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
|
||||
```kotlin
|
||||
@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
|
||||
```kotlin
|
||||
@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:
|
||||
|
||||
```kotlin
|
||||
@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
|
||||
|
||||
```kotlin
|
||||
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.
|
||||
Reference in New Issue
Block a user