원클릭으로
ui-components
Design system, UI components, Screen, Toolbar, Sheet, and localization reference.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Design system, UI components, Screen, Toolbar, Sheet, and localization reference.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Implement UI from Figma designs via MCP with a closed-loop pixel-parity check. Extract exact values (never eyeball), translate to SwiftUI, then render→diff→fix against the Figma export until it matches. Use when implementing or auditing UI against Figma.
HTTP networking layer reference — TargetType, HTTPClient, services, error handling.
Fetch CodeRabbit review comments from batch PRs and auto-fix the issues. Pushes fixes and re-requests review.
Run multiple tasks overnight as parallel PRs. Produces a PRD per task, selects skills/rules, spawns isolated agents, and reports PR links.
Run multiple tasks overnight as parallel PRs. Produces a PRD per task, selects skills/rules, spawns isolated agents, and reports PR links.
Run SwiftLint and xcodebuild to verify the project compiles cleanly.
| name | ui-components |
| description | Design system, UI components, Screen, Toolbar, Sheet, and localization reference. |
| user-invocable | false |
Always use the Theme enum for colors and fonts. Never hardcode values.
Theme.colors.*)// Backgrounds
Theme.colors.bgPrimary // #02122B - Main background (dark navy)
Theme.colors.bgSurface1 // #061B3A - Card/container background
Theme.colors.bgSurface2 // #11284A - Elevated surface
Theme.colors.bgButtonPrimary // #33E6BF - Primary button (turquoise)
Theme.colors.bgButtonSecondary // #061B3A - Secondary button
Theme.colors.bgButtonTertiary // #2155DF - Tertiary button (blue)
// Text
Theme.colors.textPrimary // #F0F4FC - Primary text (light)
Theme.colors.textSecondary // #C9D6E8 - Secondary text
Theme.colors.textTertiary // #8295AE - Tertiary text
// Borders & Alerts
Theme.colors.border // #1B3F73 - Border color
Theme.colors.alertSuccess // #13C89D - Success (mint green)
Theme.colors.alertError // #FF5C5C - Error (red)
Theme.colors.alertWarning // #FFC25C - Warning (orange)
Theme.colors.turquoise // #33E6BF - Brand turquoise
Reference: VultisigApp/VultisigApp/Core/DesignSystem/DefaultTheme/ColorSystem.swift
Theme.fonts.*)// Brockmann family - UI text
Theme.fonts.heroDisplay // 72pt - Hero text
Theme.fonts.headline // 40pt - Headlines
Theme.fonts.title1 // 28pt - Large titles
Theme.fonts.title2 // 22pt - Medium titles
Theme.fonts.title3 // 17pt - Small titles
Theme.fonts.bodyLMedium // 18pt - Large body
Theme.fonts.bodyMMedium // 16pt - Medium body (most common)
Theme.fonts.bodySMedium // 14pt - Small body
Theme.fonts.caption12 // 12pt - Captions
Theme.fonts.buttonRegularSemibold // 16pt - Button text
// Satoshi family - ALWAYS use for numbers, prices, and balances
Theme.fonts.priceTitle1 // 28pt
Theme.fonts.priceBodyL // 18pt
Theme.fonts.priceBodyS // 14pt
Reference: VultisigApp/VultisigApp/Core/DesignSystem/DefaultTheme/FontSystem.swift
LinearGradient.primaryGradient // Turquoise -> Blue (diagonal)
LinearGradient.primaryGradientLinear // Turquoise -> Blue (vertical)
LinearGradient.primaryGradientHorizontal // Turquoise -> Blue (horizontal)
Use PrimaryButton for all buttons. Never create custom button styles.
PrimaryButton(title: "Continue", type: .primary, size: .medium) {
// action
}
// With icons
PrimaryButton(title: "Send", leadingIcon: "arrow.up", type: .primary, size: .medium) { }
// Loading state
PrimaryButton(title: "Processing", isLoading: true, type: .primary, size: .medium) { }
Button Types:
| Type | Appearance |
|---|---|
.primary | Blue background (#2155DF) |
.secondary | Dark background with border |
.primarySuccess | Turquoise background (#33E6BF) |
.alert | Red background (#FF5C5C) |
.outline | Transparent with border |
Button Sizes: .medium (full width, 14pt padding), .small (12pt), .mini (6pt), .squared (12pt radius)
Reference: VultisigApp/VultisigApp/Components/Buttons/PrimaryButton/
General-purpose text input:
@State private var text = ""
@State private var error: String? = nil
@State private var isValid: Bool? = nil
CommonTextField(
text: $text,
label: "Address",
placeholder: "Enter wallet address",
error: $error,
isValid: $isValid
)
Sizes: .normal, .small
Reference: VultisigApp/VultisigApp/Components/TextField/CommonTextField.swift
| Component | Location | Purpose |
|---|---|---|
AddressTextField | Components/Forms/AddressTextField.swift | Address input with QR/paste accessories |
AmountTextField | Components/Forms/AmountTextField.swift | Amount with percentage + ticker |
PercentageButtonsStack | Components/Forms/PercentageButtonsStack.swift | 25/50/75/100% quick-select |
PercentageSliderView | Components/Forms/PercentageSliderView.swift | Percentage slider input |
MemoTextField | Components/TextFields/MemoTextField.swift | Memo/note input |
SearchTextField | Components/TextField/SearchTextField.swift | Search input |
Standard wrapper for all full-screen views. Always use Screen for screens and suffix the struct name with Screen.
struct MyFeatureScreen: View {
var body: some View {
Screen(title: "myFeature".localized) {
ScrollView(showsIndicators: false) {
LazyVStack(spacing: 14) {
// content
}
}
}
}
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
title | String | "" | Navigation bar title |
showNavigationBar | Bool | true | Show/hide nav bar |
edgeInsets | ScreenEdgeInsets | .noInsets | Custom padding |
backgroundType | BackgroundType | .plain | .plain or .gradient |
Default padding: iOS 16pt horizontal / macOS 40pt horizontal, 12pt vertical
// Custom insets
Screen(title: "Title", edgeInsets: ScreenEdgeInsets(bottom: 0)) { ... }
// Gradient background (for main screens like Home)
Screen(title: "Title", backgroundType: .gradient) { ... }
Reference: VultisigApp/VultisigApp/Components/Screen/Screen.swift
Unified toolbar for iOS and macOS.
content
.crossPlatformToolbar("Screen Title") {
CustomToolbarItem(placement: .trailing) {
ToolbarButton(image: "gear", action: onSettings)
}
}
Parameters: navigationTitle: String?, ignoresTopEdge: Bool = false, showsBackButton: Bool = true, items: [CustomToolbarItem]
ToolbarButton types: .outline (default), .confirmation (blue), .destructive (red)
ToolbarButton(image: "checkmark", type: .confirmation, action: onConfirm)
ToolbarButton(image: "trash", type: .destructive, action: onDelete)
ToolbarButton(image: "x", iconSize: 16, action: onClose)
Reference: VultisigApp/VultisigApp/Components/Toolbar/CrossPlatformToolbar/
Unified sheet presentation for iOS and macOS.
// Boolean
.crossPlatformSheet(isPresented: $showSheet) {
MySheetContent()
}
// Item-based (item must be Identifiable & Equatable)
.crossPlatformSheet(item: $selectedItem) { item in
ItemDetailSheet(item: item)
}
Sheet content should include:
.presentationDetents([.medium, .large])
.presentationBackground(Theme.colors.bgSurface1)
.presentationDragIndicator(.visible)
Reference: VultisigApp/VultisigApp/Components/Sheet/CrossPlatformSheet.swift
// Modifier approach
VStack { ... }
.containerStyle(padding: 16, radius: 12, bgColor: Theme.colors.bgSurface1)
// Component approach
ContainerView { ... }
Reference: VultisigApp/VultisigApp/Components/Layout/ContainerView.swift
Icon(named: "arrow.up", color: Theme.colors.primaryAccent4, size: 20)
Icon(named: "checkmark", isSystem: true) // SF Symbol
Available in Components/Cells/:
| Cell | Purpose |
|---|---|
VaultCell | Vault display with name, share info |
ChainCell | Chain display |
CoinPickerCell | Coin selection |
TransactionCell | Transaction history row |
UTXOTransactionCell | UTXO-specific transaction |
SettingCell | Settings row |
SettingToggleCell | Settings with toggle |
SettingFAQCell | FAQ setting row |
SettingSelectionCell | Settings with selection |
SwapChainCell / SwapCoinCell | Swap selection |
PeerCell / EmptyPeerCell | Peer device display |
FolderCell / FolderVaultCell | Folder organization |
AddressBookCell | Address book entry |
Banners: Components/Banners/
InfoBannerView - Info banner with icon, title, messageBannerView - Basic bannerActionBannerView - Banner with action buttonOutlinedDisclaimer - Outlined disclaimer boxWarningView - Warning messageLoaders: Components/Loaders/
Loader - Main spinnerCircularProgressIndicator - Circular progress with percentageLoadingOverlayViewModifier - Blocking loading overlaySegmentedControl(...) // Standard variant
FilledSegmentedControl(...) // Filled/solid variant
Reference: Components/SegmentedControls/
// Conditional display
.showIf(condition)
// Conditional transformation
.if(condition) { view in view.opacity(0.5) }
// Optional unwrap
.unwrap(optionalValue) { view, value in ... }
// Plain list item (removes background, insets, separator)
.plainListItem()
// Sheet styling (platform-aware)
.sheetStyle(padding: 8)
References: Core/Extensions/ViewExtension.swift, Components/List/View+PlainListItem.swift, Components/Sheet/View+SheetStyling.swift
struct MyFeatureScreen: View {
@State private var showDetailSheet = false
@State private var selectedItem: Item?
var body: some View {
Screen(title: "myFeature".localized) {
ScrollView {
LazyVStack(spacing: 14) {
ForEach(items) { item in
ItemRow(item: item)
.onTapGesture { selectedItem = item }
}
}
}
}
.crossPlatformToolbar {
CustomToolbarItem(placement: .trailing) {
ToolbarButton(image: "plus") { showDetailSheet = true }
}
}
.crossPlatformSheet(isPresented: $showDetailSheet) {
AddItemSheet(isPresented: $showDetailSheet)
}
.crossPlatformSheet(item: $selectedItem) { item in
ItemDetailSheet(item: item)
}
}
}
| Language | Directory |
|---|---|
| English (base) | VultisigApp/VultisigApp/Core/Localizables/en.lproj/Localizable.strings |
| German | VultisigApp/VultisigApp/Core/Localizables/de.lproj/Localizable.strings |
| Spanish | VultisigApp/VultisigApp/Core/Localizables/es.lproj/Localizable.strings |
| Croatian | VultisigApp/VultisigApp/Core/Localizables/hr.lproj/Localizable.strings |
| Italian | VultisigApp/VultisigApp/Core/Localizables/it.lproj/Localizable.strings |
| Portuguese | VultisigApp/VultisigApp/Core/Localizables/pt.lproj/Localizable.strings |
| Simplified Chinese | VultisigApp/VultisigApp/Core/Localizables/zh-Hans.lproj/Localizable.strings |
"key".localized"sendCryptoTitle", "vaultSettings"sort_localizable.py after adding keys:
python3 VultisigApp/scripts/sort_localizable.py VultisigApp/VultisigApp/Core/Localizables/en.lproj/Localizable.strings
In Swift code:
Text("sendCryptoTitle".localized)
In each Localizable.strings:
// en.lproj
"sendCryptoTitle" = "Send Crypto";
// de.lproj
"sendCryptoTitle" = "Krypto senden";
// es.lproj
"sendCryptoTitle" = "Enviar Cripto";
// hr.lproj
"sendCryptoTitle" = "Posalji Kripto";
// it.lproj
"sendCryptoTitle" = "Invia Crypto";
// pt.lproj
"sendCryptoTitle" = "Enviar Cripto";
// zh-Hans.lproj
"sendCryptoTitle" = "发送加密货币";