Files
Seth Hobson 1e54d186fe 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)
2026-01-19 16:22:13 -05:00

605 lines
16 KiB
Markdown

# 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()
}
}
}
```