搜索

PythonReactSEOPDF
GitHub Skill

design-to-swiftui

Convert design specifications from Figma, Sketch, or Penpot to SwiftUI view code with proper modifiers and theme integration

aRustyDev☆ 6 仓库 Stars2 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

Design to SwiftUI

Convert design component specifications to SwiftUI view code.

Overview

This skill transforms design specifications (from Figma, Sketch, or Penpot) into idiomatic SwiftUI views with proper modifiers, layout containers, and theme token integration.

This skill covers:

  • Converting design frames to SwiftUI layouts (VStack, HStack, ZStack)
  • Mapping design properties to SwiftUI modifiers
  • Generating reusable SwiftUI components
  • Integrating with extracted design tokens

This skill does NOT cover:

  • Design token extraction (see design-tokens-extraction skill)
  • State management and data binding
  • Navigation and routing

Quick Reference

Design to SwiftUI Mapping
Design Element SwiftUI Component
Horizontal layout HStack
Vertical layout VStack
Overlapping layers ZStack
Auto-layout Stack with spacing
Grid LazyVGrid / LazyHGrid
Scroll container ScrollView
Text Text with modifiers
Rectangle RoundedRectangle or Rectangle
Circle Circle
Image Image / AsyncImage
Button Button with custom label
Property Mapping
Design Property SwiftUI Modifier
Fill color .fill() / .foregroundStyle()
Stroke .stroke() / .overlay()
Corner radius .clipShape(RoundedRectangle())
Shadow .shadow()
Opacity .opacity()
Padding .padding()
Size .frame()
Position .offset() / .position()

Workflow: Convert Design Component

Step 1: Analyze Design Structure

Read the design component from MCP and identify:

  • Layout type (horizontal, vertical, grid, free-form)
  • Child elements and their order
  • Spacing and padding values
  • Constraints and sizing behavior
Step 2: Map to SwiftUI Layout

Auto-layout (horizontal):

HStack(alignment: .<alignment>, spacing: <gap>) {
    // children
}

Auto-layout (vertical):

VStack(alignment: .<alignment>, spacing: <gap>) {
    // children
}

Grid layout:

let columns = [
    GridItem(.flexible()),
    GridItem(.flexible())
]
LazyVGrid(columns: columns, spacing: <gap>) {
    // children
}

Absolute positioning (rare in SwiftUI):

ZStack {
    // position children with .offset() or .position()
}
Step 3: Generate View Code

For each design element, generate SwiftUI code:

Text elements:

Text("<content>")
    .font(<Theme.Typography.style>)
    .foregroundStyle(<Theme.Colors.color>)
    .lineLimit(<lines>)
    .multilineTextAlignment(.<alignment>)

Shapes with fill:

RoundedRectangle(cornerRadius: Theme.Radius.<size>)
    .fill(Theme.Colors.<color>)
    .frame(width: <width>, height: <height>)
    .shadow(color: .black.opacity(0.1), radius: 4, y: 2)

Images:

// Local image
Image("<assetName>")
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: <width>, height: <height>)
    .clipShape(RoundedRectangle(cornerRadius: Theme.Radius.<size>))

// Remote image
AsyncImage(url: URL(string: "<url>")) { image in
    image
        .resizable()
        .aspectRatio(contentMode: .fill)
} placeholder: {
    ProgressView()
}
.frame(width: <width>, height: <height>)

Buttons:

Button {
    // action
} label: {
    HStack(spacing: 8) {
        Image(systemName: "<icon>")
        Text("<label>")
    }
    .font(Theme.Typography.<style>)
    .foregroundStyle(Theme.Colors.<textColor>)
    .padding(.horizontal, Theme.Spacing.<h>)
    .padding(.vertical, Theme.Spacing.<v>)
    .background(Theme.Colors.<bgColor>)
    .clipShape(RoundedRectangle(cornerRadius: Theme.Radius.<size>))
}
Step 4: Create Component View

Wrap the generated code in a reusable SwiftUI View:

import SwiftUI

struct <ComponentName>View: View {
    // Properties extracted from design variants
    let title: String
    let subtitle: String?
    var onTap: (() -> Void)?

    var body: some View {
        VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
            Text(title)
                .font(Theme.Typography.headlineMedium)
                .foregroundStyle(Theme.Colors.text)

            if let subtitle {
                Text(subtitle)
                    .font(Theme.Typography.bodyMedium)
                    .foregroundStyle(Theme.Colors.textSecondary)
            }
        }
        .padding(Theme.Spacing.md)
        .background(Theme.Colors.surface)
        .clipShape(RoundedRectangle(cornerRadius: Theme.Radius.md))
        .onTapGesture {
            onTap?()
        }
    }
}

#Preview {
    <ComponentName>View(
        title: "Preview Title",
        subtitle: "Preview subtitle text"
    )
    .padding()
}

Common Patterns

Card Component

Design spec:

  • Background fill with rounded corners
  • Shadow elevation
  • Padding around content
  • Optional image header
struct CardView<Content: View>: View {
    let content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            content
        }
        .background(Theme.Colors.surface)
        .clipShape(RoundedRectangle(cornerRadius: Theme.Radius.lg))
        .shadow(
            color: .black.opacity(0.08),
            radius: 8,
            y: 4
        )
    }
}
Button Variants

Design spec defines Primary, Secondary, Ghost variants:

enum ButtonVariant {
    case primary, secondary, ghost

    var backgroundColor: Color {
        switch self {
        case .primary: Theme.Colors.primary
        case .secondary: Theme.Colors.surface
        case .ghost: .clear
        }
    }

    var foregroundColor: Color {
        switch self {
        case .primary: Theme.Colors.onPrimary
        case .secondary: Theme.Colors.primary
        case .ghost: Theme.Colors.primary
        }
    }
}

struct ThemedButton: View {
    let title: String
    let variant: ButtonVariant
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            Text(title)
                .font(Theme.Typography.labelLarge)
                .foregroundStyle(variant.foregroundColor)
                .padding(.horizontal, Theme.Spacing.lg)
                .padding(.vertical, Theme.Spacing.md)
                .background(variant.backgroundColor)
                .clipShape(RoundedRectangle(cornerRadius: Theme.Radius.md))
        }
    }
}
List Item

Design spec with leading icon, title/subtitle, trailing accessory:

struct ListItemView: View {
    let icon: String
    let title: String
    let subtitle: String?
    let accessory: Accessory

    enum Accessory {
        case chevron
        case toggle(Binding<Bool>)
        case badge(String)
        case none
    }

    var body: some View {
        HStack(spacing: Theme.Spacing.md) {
            Image(systemName: icon)
                .font(.system(size: 20))
                .foregroundStyle(Theme.Colors.primary)
                .frame(width: 24)

            VStack(alignment: .leading, spacing: 2) {
                Text(title)
                    .font(Theme.Typography.bodyLarge)
                    .foregroundStyle(Theme.Colors.text)

                if let subtitle {
                    Text(subtitle)
                        .font(Theme.Typography.bodySmall)
                        .foregroundStyle(Theme.Colors.textSecondary)
                }
            }

            Spacer()

            accessoryView
        }
        .padding(.vertical, Theme.Spacing.sm)
        .padding(.horizontal, Theme.Spacing.md)
    }

    @ViewBuilder
    private var accessoryView: some View {
        switch accessory {
        case .chevron:
            Image(systemName: "chevron.right")
                .foregroundStyle(Theme.Colors.textSecondary)
        case .toggle(let isOn):
            Toggle("", isOn: isOn)
                .labelsHidden()
        case .badge(let text):
            Text(text)
                .font(Theme.Typography.labelSmall)
                .padding(.horizontal, 8)
                .padding(.vertical, 4)
                .background(Theme.Colors.primary)
                .foregroundStyle(Theme.Colors.onPrimary)
                .clipShape(Capsule())
        case .none:
            EmptyView()
        }
    }
}

Token Integration

Reference design tokens through the Theme struct:

// Colors
Theme.Colors.primary
Theme.Colors.surface
Theme.Colors.text
Theme.Colors.textSecondary

// Typography
Theme.Typography.displayLarge
Theme.Typography.headlineMedium
Theme.Typography.bodyLarge
Theme.Typography.labelSmall

// Spacing
Theme.Spacing.xs  // 4
Theme.Spacing.sm  // 8
Theme.Spacing.md  // 16
Theme.Spacing.lg  // 24
Theme.Spacing.xl  // 32

// Corner Radius
Theme.Radius.sm   // 4
Theme.Radius.md   // 8
Theme.Radius.lg   // 16
Theme.Radius.full // 9999

Naming Conventions

Design Name SwiftUI Name
Button/Primary PrimaryButton
Card - Article ArticleCardView
List Item/Default ListItemView
Header/Large LargeHeaderView
Input/Text Field TextFieldView

See Also

  • design-tokens-extraction skill - Extract tokens first
  • design-token-swift style - Swift code output format
  • swiftui-components skill - SwiftUI component patterns

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-03-11
索引更新时间
2026-03-11
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!