From swift-design-system
デザインシステム準拠のSwiftUIコンポーネントを生成する。新しいUIパーツの作成、コンポーネント生成時に使用。「コンポーネント作成」「新しいUI」「パーツ作成」「component generate」「UIパーツ」「新規コンポーネント」などのキーワードで自動適用。
npx claudepluginhub no-problem-dev/claude-code-plugins --plugin swift-design-systemThis skill uses the workspace's default tool permissions.
Swift Design System に準拠した新規 SwiftUI コンポーネントを生成するためのガイド。
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
Swift Design System に準拠した新規 SwiftUI コンポーネントを生成するためのガイド。
コンポーネントを生成する前に、以下を確認すること:
import SwiftUI
import DesignSystem
/// コンポーネントの説明
///
/// 使用場面と目的を記述。
///
/// ## 使用例
/// ```swift
/// MyComponent(title: "タイトル") {
/// Text("コンテンツ")
/// }
/// ```
public struct MyComponent<Content: View>: View {
// MARK: - Environment(必要なトークンのみ宣言)
@Environment(\.colorPalette) private var colors
@Environment(\.spacingScale) private var spacing
@Environment(\.radiusScale) private var radius
@Environment(\.motion) private var motion
// MARK: - Properties
private let title: String
private let content: Content
// MARK: - Init
public init(
title: String,
@ViewBuilder content: () -> Content
) {
self.title = title
self.content = content()
}
// MARK: - Body
public var body: some View {
VStack(alignment: .leading, spacing: spacing.md) {
Text(title)
.typography(.titleMedium)
.foregroundStyle(colors.onSurface)
content
}
.padding(spacing.lg)
.background(colors.surface)
.clipShape(RoundedRectangle(cornerRadius: radius.lg))
.elevation(.level1)
.accessibilityElement(children: .contain)
.accessibilityLabel(title)
}
}
// 必要なトークンのみ宣言する
@Environment(\.colorPalette) private var colors
@Environment(\.spacingScale) private var spacing
@Environment(\.radiusScale) private var radius
@Environment(\.motion) private var motion
#Preview {
MyComponent(title: "サンプル") {
Text("コンテンツ")
}
.padding()
.theme(ThemeProvider())
}
// Typography
Text("見出し").typography(.headlineLarge)
// Elevation
Card { content }.elevation(.level2)
// Animation(reduce motion を自動尊重)
.animate(motion.tap, value: isPressed)
// ラベル
.accessibilityLabel("説明テキスト")
// 最小タップターゲット 44x44pt
.frame(minWidth: 44, minHeight: 44)
// セマンティクス
.accessibilityElement(children: .contain)
.accessibilityAddTraits(.isButton) // インタラクティブ要素の場合
// SF Symbols を使用
Image(systemName: "star.fill")
.foregroundStyle(colors.primary)
// IconBadge コンポーネント
IconBadge(systemName: "bell.fill", size: .medium)
最低5つの Preview を用意すること:
// 1. デフォルト状態
#Preview("Default") {
MyComponent(title: "デフォルト") {
Text("通常表示")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
}
// 2. ダークモード
#Preview("Dark Mode") {
MyComponent(title: "ダークモード") {
Text("ダーク表示")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider(initialMode: .dark))
}
// 3. 大きなテキスト (Dynamic Type)
#Preview("Large Text") {
MyComponent(title: "大きなテキスト") {
Text("Dynamic Type 対応確認")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
.environment(\.sizeCategory, .accessibilityExtraLarge)
}
// 4. コンパクト (最小コンテンツ)
#Preview("Compact") {
MyComponent(title: "短") {
Text("OK")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
}
// 5. エッジケース (長いテキスト、大量データ)
#Preview("Edge Case") {
MyComponent(title: "非常に長いタイトルが入った場合の表示確認テスト") {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
}
// ✅ Good: セマンティックカラー
.foregroundStyle(colors.onSurface)
.background(colors.surface)
// ❌ Bad: ハードコード
.foregroundColor(.black)
.background(Color.white)
// ✅ Good: トークン使用
VStack(spacing: spacing.md) { ... }
.padding(spacing.lg)
// ❌ Bad: マジックナンバー
VStack(spacing: 12) { ... }
.padding(16)
// ✅ Good: RadiusScale 使用
.clipShape(RoundedRectangle(cornerRadius: radius.lg))
// ❌ Bad: 直値
.clipShape(RoundedRectangle(cornerRadius: 12))
// ✅ Good: Motion トークン + animate モディファイア
.animate(motion.tap, value: isPressed)
// ❌ Bad: 直接アニメーション指定(reduce motion 無視)
.animation(.easeOut(duration: 0.1), value: isPressed)
// ✅ Good: 既存コンポーネント使用
Card(elevation: .level2) { content }
Button("保存") { save() }.buttonStyle(.primary)
// ❌ Bad: 独自実装
RoundedRectangle(cornerRadius: 8).fill(Color.white).shadow(radius: 4)
// ✅ Good: typography モディファイア
Text("見出し").typography(.headlineLarge)
// ❌ Bad: 直接フォント指定
Text("見出し").font(.system(size: 32, weight: .semibold))
colorPalette 経由かspacingScale 経由かradiusScale 経由かmotion トークン + .animate() を使用しているか.typography() モディファイアを使用しているかaccessibilityLabel が設定されているか.theme(ThemeProvider()) が付いているかimport DesignSystem があるか