mirror of
https://github.com/wshobson/agents.git
synced 2026-03-18 09:37:15 +00:00
feat(ui-design): add comprehensive UI/UX design plugin v1.0.0
New plugin covering mobile (iOS, Android, React Native) and web applications with modern design patterns, accessibility, and design systems. Components: - 9 skills: design-system-patterns, accessibility-compliance, responsive-design, mobile-ios-design, mobile-android-design, react-native-design, web-component-design, interaction-design, visual-design-foundations - 4 commands: design-review, create-component, accessibility-audit, design-system-setup - 3 agents: ui-designer, accessibility-expert, design-system-architect Marketplace updated: - Version bumped to 1.3.4 - 102 agents (+3), 116 skills (+9)
This commit is contained in:
@@ -0,0 +1,604 @@
|
||||
# Material Design 3 Theming
|
||||
|
||||
## Color System
|
||||
|
||||
### Dynamic Color (Material You)
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun AppTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context)
|
||||
else dynamicLightColorScheme(context)
|
||||
}
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = AppTypography,
|
||||
shapes = AppShapes,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Color Scheme
|
||||
|
||||
```kotlin
|
||||
// Define color palette
|
||||
val md_theme_light_primary = Color(0xFF6750A4)
|
||||
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_primaryContainer = Color(0xFFEADDFF)
|
||||
val md_theme_light_onPrimaryContainer = Color(0xFF21005D)
|
||||
val md_theme_light_secondary = Color(0xFF625B71)
|
||||
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_secondaryContainer = Color(0xFFE8DEF8)
|
||||
val md_theme_light_onSecondaryContainer = Color(0xFF1D192B)
|
||||
val md_theme_light_tertiary = Color(0xFF7D5260)
|
||||
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_tertiaryContainer = Color(0xFFFFD8E4)
|
||||
val md_theme_light_onTertiaryContainer = Color(0xFF31111D)
|
||||
val md_theme_light_error = Color(0xFFB3261E)
|
||||
val md_theme_light_onError = Color(0xFFFFFFFF)
|
||||
val md_theme_light_errorContainer = Color(0xFFF9DEDC)
|
||||
val md_theme_light_onErrorContainer = Color(0xFF410E0B)
|
||||
val md_theme_light_background = Color(0xFFFFFBFE)
|
||||
val md_theme_light_onBackground = Color(0xFF1C1B1F)
|
||||
val md_theme_light_surface = Color(0xFFFFFBFE)
|
||||
val md_theme_light_onSurface = Color(0xFF1C1B1F)
|
||||
val md_theme_light_surfaceVariant = Color(0xFFE7E0EC)
|
||||
val md_theme_light_onSurfaceVariant = Color(0xFF49454F)
|
||||
val md_theme_light_outline = Color(0xFF79747E)
|
||||
val md_theme_light_outlineVariant = Color(0xFFCAC4D0)
|
||||
|
||||
val LightColorScheme = lightColorScheme(
|
||||
primary = md_theme_light_primary,
|
||||
onPrimary = md_theme_light_onPrimary,
|
||||
primaryContainer = md_theme_light_primaryContainer,
|
||||
onPrimaryContainer = md_theme_light_onPrimaryContainer,
|
||||
secondary = md_theme_light_secondary,
|
||||
onSecondary = md_theme_light_onSecondary,
|
||||
secondaryContainer = md_theme_light_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_light_onSecondaryContainer,
|
||||
tertiary = md_theme_light_tertiary,
|
||||
onTertiary = md_theme_light_onTertiary,
|
||||
tertiaryContainer = md_theme_light_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_light_onTertiaryContainer,
|
||||
error = md_theme_light_error,
|
||||
onError = md_theme_light_onError,
|
||||
errorContainer = md_theme_light_errorContainer,
|
||||
onErrorContainer = md_theme_light_onErrorContainer,
|
||||
background = md_theme_light_background,
|
||||
onBackground = md_theme_light_onBackground,
|
||||
surface = md_theme_light_surface,
|
||||
onSurface = md_theme_light_onSurface,
|
||||
surfaceVariant = md_theme_light_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_light_onSurfaceVariant,
|
||||
outline = md_theme_light_outline,
|
||||
outlineVariant = md_theme_light_outlineVariant
|
||||
)
|
||||
|
||||
// Dark colors follow the same pattern
|
||||
val DarkColorScheme = darkColorScheme(
|
||||
primary = md_theme_dark_primary,
|
||||
// ... other colors
|
||||
)
|
||||
```
|
||||
|
||||
### Color Roles Usage
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun ColorRolesExample() {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// Primary - Key actions, FABs
|
||||
Button(onClick = { }) {
|
||||
Text("Primary Action")
|
||||
}
|
||||
|
||||
// Primary Container - Less prominent containers
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.primaryContainer,
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
) {
|
||||
Text(
|
||||
"Primary Container",
|
||||
modifier = Modifier.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
)
|
||||
}
|
||||
|
||||
// Secondary - Less prominent actions
|
||||
FilledTonalButton(onClick = { }) {
|
||||
Text("Secondary Action")
|
||||
}
|
||||
|
||||
// Tertiary - Contrast accents
|
||||
Badge(
|
||||
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
|
||||
) {
|
||||
Text("New")
|
||||
}
|
||||
|
||||
// Error - Destructive actions
|
||||
Button(
|
||||
onClick = { },
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.error
|
||||
)
|
||||
) {
|
||||
Text("Delete")
|
||||
}
|
||||
|
||||
// Surface variants
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Text(
|
||||
"Surface Variant",
|
||||
modifier = Modifier.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Extended Colors
|
||||
|
||||
```kotlin
|
||||
// Custom semantic colors beyond M3 defaults
|
||||
data class ExtendedColors(
|
||||
val success: Color,
|
||||
val onSuccess: Color,
|
||||
val successContainer: Color,
|
||||
val onSuccessContainer: Color,
|
||||
val warning: Color,
|
||||
val onWarning: Color,
|
||||
val warningContainer: Color,
|
||||
val onWarningContainer: Color
|
||||
)
|
||||
|
||||
val LocalExtendedColors = staticCompositionLocalOf {
|
||||
ExtendedColors(
|
||||
success = Color(0xFF4CAF50),
|
||||
onSuccess = Color.White,
|
||||
successContainer = Color(0xFFE8F5E9),
|
||||
onSuccessContainer = Color(0xFF1B5E20),
|
||||
warning = Color(0xFFFF9800),
|
||||
onWarning = Color.White,
|
||||
warningContainer = Color(0xFFFFF3E0),
|
||||
onWarningContainer = Color(0xFFE65100)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppTheme(
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val extendedColors = ExtendedColors(
|
||||
// ... define colors based on light/dark theme
|
||||
)
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalExtendedColors provides extendedColors
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
@Composable
|
||||
fun SuccessBanner() {
|
||||
val extendedColors = LocalExtendedColors.current
|
||||
|
||||
Surface(
|
||||
color = extendedColors.successContainer,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.CheckCircle,
|
||||
contentDescription = null,
|
||||
tint = extendedColors.success
|
||||
)
|
||||
Text(
|
||||
"Operation successful!",
|
||||
color = extendedColors.onSuccessContainer
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Typography
|
||||
|
||||
### Material 3 Type Scale
|
||||
|
||||
```kotlin
|
||||
val AppTypography = Typography(
|
||||
// Display styles - Hero text, large numerals
|
||||
displayLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 57.sp,
|
||||
lineHeight = 64.sp,
|
||||
letterSpacing = (-0.25).sp
|
||||
),
|
||||
displayMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 45.sp,
|
||||
lineHeight = 52.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
displaySmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 36.sp,
|
||||
lineHeight = 44.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
|
||||
// Headline styles - High emphasis, short text
|
||||
headlineLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 32.sp,
|
||||
lineHeight = 40.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
headlineMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 36.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
headlineSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 24.sp,
|
||||
lineHeight = 32.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
|
||||
// Title styles - Medium emphasis headers
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
titleMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.15.sp
|
||||
),
|
||||
titleSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.1.sp
|
||||
),
|
||||
|
||||
// Body styles - Long-form text
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
),
|
||||
bodyMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.25.sp
|
||||
),
|
||||
bodySmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.4.sp
|
||||
),
|
||||
|
||||
// Label styles - Buttons, chips, navigation
|
||||
labelLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.1.sp
|
||||
),
|
||||
labelMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
### Custom Fonts
|
||||
|
||||
```kotlin
|
||||
// Load custom fonts
|
||||
val Inter = FontFamily(
|
||||
Font(R.font.inter_regular, FontWeight.Normal),
|
||||
Font(R.font.inter_medium, FontWeight.Medium),
|
||||
Font(R.font.inter_semibold, FontWeight.SemiBold),
|
||||
Font(R.font.inter_bold, FontWeight.Bold)
|
||||
)
|
||||
|
||||
val AppTypography = Typography(
|
||||
displayLarge = TextStyle(
|
||||
fontFamily = Inter,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 57.sp,
|
||||
lineHeight = 64.sp
|
||||
),
|
||||
// Apply to all styles...
|
||||
)
|
||||
|
||||
// Variable fonts (Android 12+)
|
||||
val InterVariable = FontFamily(
|
||||
Font(
|
||||
R.font.inter_variable,
|
||||
variationSettings = FontVariation.Settings(
|
||||
FontVariation.weight(400)
|
||||
)
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
## Shape System
|
||||
|
||||
### Material 3 Shapes
|
||||
|
||||
```kotlin
|
||||
val AppShapes = Shapes(
|
||||
// Extra small - Chips, small buttons
|
||||
extraSmall = RoundedCornerShape(4.dp),
|
||||
|
||||
// Small - Text fields, small cards
|
||||
small = RoundedCornerShape(8.dp),
|
||||
|
||||
// Medium - Cards, dialogs
|
||||
medium = RoundedCornerShape(12.dp),
|
||||
|
||||
// Large - Large cards, bottom sheets
|
||||
large = RoundedCornerShape(16.dp),
|
||||
|
||||
// Extra large - Full-screen dialogs
|
||||
extraLarge = RoundedCornerShape(28.dp)
|
||||
)
|
||||
```
|
||||
|
||||
### Custom Shape Usage
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun ShapedComponents() {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// Small shape for text field
|
||||
OutlinedTextField(
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
shape = MaterialTheme.shapes.small,
|
||||
label = { Text("Input") }
|
||||
)
|
||||
|
||||
// Medium shape for cards
|
||||
Card(
|
||||
shape = MaterialTheme.shapes.medium
|
||||
) {
|
||||
Text("Card content", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
|
||||
// Large shape for prominent containers
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.large,
|
||||
color = MaterialTheme.colorScheme.primaryContainer
|
||||
) {
|
||||
Text("Featured", modifier = Modifier.padding(24.dp))
|
||||
}
|
||||
|
||||
// Custom asymmetric shape
|
||||
Surface(
|
||||
shape = RoundedCornerShape(
|
||||
topStart = 24.dp,
|
||||
topEnd = 24.dp,
|
||||
bottomStart = 0.dp,
|
||||
bottomEnd = 0.dp
|
||||
),
|
||||
color = MaterialTheme.colorScheme.surface
|
||||
) {
|
||||
Text("Bottom sheet style", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Elevation and Shadows
|
||||
|
||||
### Tonal Elevation
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun ElevationExample() {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// Level 0 - No elevation
|
||||
Surface(
|
||||
tonalElevation = 0.dp,
|
||||
shadowElevation = 0.dp
|
||||
) {
|
||||
Text("Level 0", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
|
||||
// Level 1 - Low emphasis surfaces
|
||||
Surface(
|
||||
tonalElevation = 1.dp,
|
||||
shadowElevation = 1.dp
|
||||
) {
|
||||
Text("Level 1", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
|
||||
// Level 2 - Cards, switches
|
||||
Surface(
|
||||
tonalElevation = 3.dp,
|
||||
shadowElevation = 2.dp
|
||||
) {
|
||||
Text("Level 2", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
|
||||
// Level 3 - Navigation components
|
||||
Surface(
|
||||
tonalElevation = 6.dp,
|
||||
shadowElevation = 4.dp
|
||||
) {
|
||||
Text("Level 3", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
|
||||
// Level 4 - Navigation rail
|
||||
Surface(
|
||||
tonalElevation = 8.dp,
|
||||
shadowElevation = 6.dp
|
||||
) {
|
||||
Text("Level 4", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
|
||||
// Level 5 - FAB
|
||||
Surface(
|
||||
tonalElevation = 12.dp,
|
||||
shadowElevation = 8.dp
|
||||
) {
|
||||
Text("Level 5", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Responsive Design
|
||||
|
||||
### Window Size Classes
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun AdaptiveLayout() {
|
||||
val windowSizeClass = calculateWindowSizeClass(LocalContext.current as Activity)
|
||||
|
||||
when (windowSizeClass.widthSizeClass) {
|
||||
WindowWidthSizeClass.Compact -> {
|
||||
// Phone portrait - Single column, bottom nav
|
||||
CompactLayout()
|
||||
}
|
||||
WindowWidthSizeClass.Medium -> {
|
||||
// Tablet portrait, phone landscape - Navigation rail
|
||||
MediumLayout()
|
||||
}
|
||||
WindowWidthSizeClass.Expanded -> {
|
||||
// Tablet landscape, desktop - Navigation drawer, multi-pane
|
||||
ExpandedLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CompactLayout() {
|
||||
Scaffold(
|
||||
bottomBar = { NavigationBar { /* items */ } }
|
||||
) { padding ->
|
||||
Content(modifier = Modifier.padding(padding))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MediumLayout() {
|
||||
Row {
|
||||
NavigationRail { /* items */ }
|
||||
Content(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ExpandedLayout() {
|
||||
PermanentNavigationDrawer(
|
||||
drawerContent = {
|
||||
PermanentDrawerSheet { /* items */ }
|
||||
}
|
||||
) {
|
||||
Row {
|
||||
ListPane(modifier = Modifier.weight(0.4f))
|
||||
DetailPane(modifier = Modifier.weight(0.6f))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Foldable Support
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun FoldableAwareLayout() {
|
||||
val foldingFeature = LocalFoldingFeature.current
|
||||
|
||||
when {
|
||||
foldingFeature?.state == FoldingFeature.State.HALF_OPENED -> {
|
||||
// Device is half-folded (tabletop mode)
|
||||
TwoHingeLayout(
|
||||
top = { CameraPreview() },
|
||||
bottom = { CameraControls() }
|
||||
)
|
||||
}
|
||||
foldingFeature?.orientation == FoldingFeature.Orientation.VERTICAL -> {
|
||||
// Vertical fold (book mode)
|
||||
TwoPaneLayout(
|
||||
first = { NavigationPane() },
|
||||
second = { ContentPane() }
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// Regular or fully opened
|
||||
SinglePaneLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user