Modern SwiftUI colors, ShapeStyle, gradients, MeshGradient, and custom ViewModifiers. Use when user asks about colors, foregroundStyle, gradients, hierarchical colors, tint, custom ViewModifiers, or SwiftUI styling.
Creates reusable SwiftUI ViewModifiers and modern color systems using foregroundStyle, gradients, and hierarchical colors.
/plugin marketplace add bluewaves-creations/bluewaves-skills/plugin install swift-apple-dev@bluewaves-skillsThis skill is limited to using the following tools:
Comprehensive guide to modern SwiftUI color APIs, ShapeStyle, gradients, and creating reusable ViewModifiers for iOS 26.
Replaces the deprecated foregroundColor(_:):
// DEPRECATED
Text("Hello")
.foregroundColor(.blue)
// MODERN - Use foregroundStyle
Text("Hello")
.foregroundStyle(.blue)
// With gradients
Text("Gradient Text")
.foregroundStyle(
LinearGradient(
colors: [.blue, .purple],
startPoint: .leading,
endPoint: .trailing
)
)
foregroundStyle accepts any ShapeStyle:
// Colors
.foregroundStyle(.red)
.foregroundStyle(Color.blue)
// Gradients
.foregroundStyle(LinearGradient(...))
.foregroundStyle(RadialGradient(...))
.foregroundStyle(AngularGradient(...))
.foregroundStyle(MeshGradient(...))
// Materials
.foregroundStyle(.ultraThinMaterial)
.foregroundStyle(.regularMaterial)
// Hierarchical
.foregroundStyle(.primary)
.foregroundStyle(.secondary)
.foregroundStyle(.tertiary)
// Set all three levels at once
ContentView()
.foregroundStyle(.red, .orange, .yellow)
// Children use hierarchical levels
struct ContentView: View {
var body: some View {
VStack {
Text("Primary") // Red
.foregroundStyle(.primary)
Text("Secondary") // Orange
.foregroundStyle(.secondary)
Text("Tertiary") // Yellow
.foregroundStyle(.tertiary)
}
}
}
.foregroundStyle(.primary) // Level 1 - Most prominent
.foregroundStyle(.secondary) // Level 2
.foregroundStyle(.tertiary) // Level 3
.foregroundStyle(.quaternary) // Level 4
.foregroundStyle(.quinary) // Level 5 - Least prominent
Note: Only first three can be customized via foregroundStyle(_:_:_:).
struct CardView: View {
let title: String
let subtitle: String
let detail: String
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.headline)
.foregroundStyle(.primary)
Text(subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
Text(detail)
.font(.caption)
.foregroundStyle(.tertiary)
}
}
}
// Adaptive colors (change with Dark Mode)
Color.primary // Black/White
Color.secondary // Gray
Color.accentColor // App's accent color
// UI element colors
Color(uiColor: .systemBackground)
Color(uiColor: .secondarySystemBackground)
Color(uiColor: .tertiarySystemBackground)
Color(uiColor: .label)
Color(uiColor: .secondaryLabel)
Set in Asset Catalog or programmatically:
// In code
Button("Action") { }
.tint(.blue)
// App-wide in Assets.xcassets:
// Create "AccentColor" color set
Override accent color for a hierarchy:
// tint affects interactive elements, not all foreground
VStack {
Button("Blue") { } // Uses blue tint
Link("Website", destination: url) // Uses blue tint
Text("Plain") // NOT affected by tint
}
.tint(.blue)
tint vs foregroundStyle:
tint: Affects buttons, links, controlsforegroundStyle: Affects all foreground contentLinearGradient(
colors: [.blue, .purple],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
// With stops for control
LinearGradient(
stops: [
.init(color: .red, location: 0),
.init(color: .orange, location: 0.3),
.init(color: .yellow, location: 1)
],
startPoint: .top,
endPoint: .bottom
)
// Usage
Rectangle()
.fill(
LinearGradient(
colors: [.blue, .cyan],
startPoint: .leading,
endPoint: .trailing
)
)
RadialGradient(
colors: [.white, .blue],
center: .center,
startRadius: 0,
endRadius: 200
)
// With offset center
RadialGradient(
colors: [.yellow, .orange, .red],
center: .topLeading,
startRadius: 50,
endRadius: 300
)
AngularGradient(
colors: [.red, .yellow, .green, .blue, .purple, .red],
center: .center
)
// Conic gradient with angle
AngularGradient(
colors: [.blue, .purple],
center: .center,
startAngle: .degrees(0),
endAngle: .degrees(180)
)
Complex multi-point gradients:
MeshGradient(
width: 3,
height: 3,
points: [
// Row 0
[0.0, 0.0], [0.5, 0.0], [1.0, 0.0],
// Row 1
[0.0, 0.5], [0.5, 0.5], [1.0, 0.5],
// Row 2
[0.0, 1.0], [0.5, 1.0], [1.0, 1.0]
],
colors: [
.red, .orange, .yellow,
.green, .blue, .purple,
.pink, .cyan, .mint
]
)
// Animated mesh
struct AnimatedMesh: View {
@State private var offset: CGFloat = 0
var body: some View {
MeshGradient(
width: 3,
height: 3,
points: [
[0.0, 0.0], [0.5, 0.0], [1.0, 0.0],
[0.0, 0.5], [0.5 + offset, 0.5], [1.0, 0.5],
[0.0, 1.0], [0.5, 1.0], [1.0, 1.0]
],
colors: [
.blue, .cyan, .teal,
.purple, .indigo, .blue,
.pink, .orange, .yellow
],
smoothsColors: true
)
.onAppear {
withAnimation(.easeInOut(duration: 2).repeatForever()) {
offset = 0.2
}
}
}
}
// By name
Color("BrandPrimary")
Color("BackgroundColor")
// With bundle
Color("CustomColor", bundle: .module)
Assets.xcassets/
├── Colors/
│ ├── Brand/
│ │ ├── BrandPrimary
│ │ ├── BrandSecondary
│ │ └── BrandAccent
│ ├── UI/
│ │ ├── BackgroundPrimary
│ │ ├── BackgroundSecondary
│ │ └── SeparatorColor
│ └── Text/
│ ├── TextPrimary
│ ├── TextSecondary
│ └── TextTertiary
struct StripedStyle: ShapeStyle {
var color1: Color
var color2: Color
var stripeWidth: CGFloat
func resolve(in environment: EnvironmentValues) -> some ShapeStyle {
// Return a resolved style
LinearGradient(
stops: generateStripeStops(),
startPoint: .leading,
endPoint: .trailing
)
}
private func generateStripeStops() -> [Gradient.Stop] {
var stops: [Gradient.Stop] = []
var position: CGFloat = 0
while position < 1 {
stops.append(.init(color: color1, location: position))
stops.append(.init(color: color1, location: position + stripeWidth / 2))
stops.append(.init(color: color2, location: position + stripeWidth / 2))
stops.append(.init(color: color2, location: position + stripeWidth))
position += stripeWidth
}
return stops
}
}
// Usage
Rectangle()
.fill(StripedStyle(color1: .blue, color2: .white, stripeWidth: 0.1))
struct CardStyle: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 12))
.shadow(radius: 4)
}
}
extension View {
func cardStyle() -> some View {
modifier(CardStyle())
}
}
// Usage
Text("Card Content")
.cardStyle()
struct RoundedStyle: ViewModifier {
var cornerRadius: CGFloat
var backgroundColor: Color
var shadowRadius: CGFloat
func body(content: Content) -> some View {
content
.padding()
.background(backgroundColor)
.clipShape(RoundedRectangle(cornerRadius: cornerRadius))
.shadow(radius: shadowRadius)
}
}
extension View {
func rounded(
cornerRadius: CGFloat = 12,
backgroundColor: Color = .white,
shadowRadius: CGFloat = 4
) -> some View {
modifier(RoundedStyle(
cornerRadius: cornerRadius,
backgroundColor: backgroundColor,
shadowRadius: shadowRadius
))
}
}
// Usage
Text("Custom")
.rounded(cornerRadius: 20, backgroundColor: .blue)
struct AdaptiveCard: ViewModifier {
@Environment(\.colorScheme) var colorScheme
func body(content: Content) -> some View {
content
.padding()
.background(colorScheme == .dark ? Color.gray.opacity(0.2) : Color.white)
.clipShape(RoundedRectangle(cornerRadius: 12))
.shadow(
color: colorScheme == .dark ? .clear : .black.opacity(0.1),
radius: 8
)
}
}
extension View {
@ViewBuilder
func `if`<Content: View>(
_ condition: Bool,
transform: (Self) -> Content
) -> some View {
if condition {
transform(self)
} else {
self
}
}
@ViewBuilder
func ifLet<T, Content: View>(
_ value: T?,
transform: (Self, T) -> Content
) -> some View {
if let value {
transform(self, value)
} else {
self
}
}
}
// Usage
Text("Hello")
.if(isHighlighted) { view in
view.foregroundStyle(.yellow)
}
.ifLet(user) { view, user in
view.badge(user.notificationCount)
}
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Dismiss", role: .close) {
dismiss()
}
// Renders as glass X button
}
}
Button("Glass") { }
.buttonStyle(.glass)
Button("Prominent") { }
.buttonStyle(.glassProminent)
Slider(value: $value, in: 0...100) {
Text("Value")
} minimumValueLabel: {
Text("0")
} maximumValueLabel: {
Text("100")
}
.sliderStyle(.ticked(count: 10)) // iOS 26
// DesignSystem.swift
enum DS {
enum Colors {
static let primary = Color("Primary")
static let secondary = Color("Secondary")
static let background = Color("Background")
static let surface = Color("Surface")
static let error = Color("Error")
static let success = Color("Success")
}
enum Spacing {
static let xs: CGFloat = 4
static let sm: CGFloat = 8
static let md: CGFloat = 16
static let lg: CGFloat = 24
static let xl: CGFloat = 32
}
enum CornerRadius {
static let sm: CGFloat = 4
static let md: CGFloat = 8
static let lg: CGFloat = 16
static let xl: CGFloat = 24
}
}
// Modifiers using design system
struct DSCard: ViewModifier {
func body(content: Content) -> some View {
content
.padding(DS.Spacing.md)
.background(DS.Colors.surface)
.clipShape(RoundedRectangle(cornerRadius: DS.CornerRadius.lg))
}
}
extension View {
func dsCard() -> some View {
modifier(DSCard())
}
}
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.