Deploy Ladill Mini / deploy (push) Successful in 35s
Ship full-featured mobile clients with auth, payments, QRs, push notifications, and iOS polish including Figtree typography, app icons, and QR previews. Co-authored-by: Cursor <cursoragent@cursor.com>
141 lines
4.4 KiB
Swift
141 lines
4.4 KiB
Swift
import SwiftUI
|
|
|
|
struct LadillButton: View {
|
|
let title: String
|
|
var loading = false
|
|
var enabled = true
|
|
let action: () -> Void
|
|
|
|
var body: some View {
|
|
Button(action: action) {
|
|
ZStack {
|
|
RoundedRectangle(cornerRadius: 28)
|
|
.fill(LadillColors.primaryGradient)
|
|
.frame(height: 56)
|
|
.opacity(enabled && !loading ? 1 : 0.5)
|
|
|
|
if loading {
|
|
ProgressView().tint(.white)
|
|
} else {
|
|
HStack {
|
|
Text(title)
|
|
.font(.ladill(size: 15, weight: .semibold))
|
|
.foregroundStyle(.white)
|
|
.frame(maxWidth: .infinity)
|
|
Circle()
|
|
.fill(.white)
|
|
.frame(width: 44, height: 44)
|
|
.overlay {
|
|
Image(systemName: "arrow.up.right")
|
|
.font(.system(size: 14, weight: .semibold))
|
|
.foregroundStyle(LadillColors.indigo)
|
|
}
|
|
}
|
|
.padding(.leading, 22)
|
|
.padding(.trailing, 6)
|
|
}
|
|
}
|
|
}
|
|
.disabled(!enabled || loading)
|
|
.buttonStyle(.plain)
|
|
}
|
|
}
|
|
|
|
struct LadillSecondaryButton: View {
|
|
let title: String
|
|
var enabled = true
|
|
let action: () -> Void
|
|
|
|
var body: some View {
|
|
Button(action: action) {
|
|
Text(title)
|
|
.font(.ladill(size: 15, weight: .semibold))
|
|
.foregroundStyle(LadillColors.ink)
|
|
.frame(maxWidth: .infinity)
|
|
.frame(height: 52)
|
|
.background(LadillColors.surfaceSoft)
|
|
.clipShape(Capsule())
|
|
.opacity(enabled ? 1 : 0.5)
|
|
}
|
|
.disabled(!enabled)
|
|
.buttonStyle(.plain)
|
|
}
|
|
}
|
|
|
|
struct LadillTextField: View {
|
|
let label: String
|
|
let placeholder: String
|
|
@Binding var text: String
|
|
var secure = false
|
|
var keyboard: UIKeyboardType = .default
|
|
var enabled = true
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
Text(label)
|
|
.font(.ladill(size: 13, weight: .medium))
|
|
.foregroundStyle(LadillColors.muted)
|
|
Group {
|
|
if secure {
|
|
SecureField(placeholder, text: $text)
|
|
} else {
|
|
TextField(placeholder, text: $text)
|
|
.keyboardType(keyboard)
|
|
.textInputAutocapitalization(keyboard == .emailAddress ? .never : .words)
|
|
.autocorrectionDisabled(keyboard == .emailAddress)
|
|
}
|
|
}
|
|
.font(.ladill(size: 16))
|
|
.padding(.horizontal, 16)
|
|
.padding(.vertical, 14)
|
|
.background(LadillColors.surface)
|
|
.overlay(RoundedRectangle(cornerRadius: 14).stroke(LadillColors.border, lineWidth: 1))
|
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
|
.disabled(!enabled)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct StepBar: View {
|
|
let current: Int
|
|
let total: Int
|
|
|
|
var body: some View {
|
|
HStack(spacing: 6) {
|
|
ForEach(0..<total, id: \.self) { index in
|
|
Capsule()
|
|
.fill(index <= current ? LadillColors.indigo : LadillColors.border)
|
|
.frame(height: 4)
|
|
}
|
|
}
|
|
.padding(.vertical, 8)
|
|
}
|
|
}
|
|
|
|
struct MenuScaffold<Content: View>: View {
|
|
let title: String
|
|
let onBack: () -> Void
|
|
@ViewBuilder let content: Content
|
|
|
|
var body: some View {
|
|
VStack(spacing: 0) {
|
|
HStack {
|
|
Button(action: onBack) {
|
|
Image(systemName: "chevron.left")
|
|
.font(.system(size: 17, weight: .semibold))
|
|
.foregroundStyle(LadillColors.ink)
|
|
}
|
|
Text(title)
|
|
.font(.ladill(size: 18, weight: .semibold))
|
|
.foregroundStyle(LadillColors.ink)
|
|
Spacer()
|
|
}
|
|
.padding(.horizontal, 16)
|
|
.padding(.vertical, 8)
|
|
content
|
|
}
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
|
.background(LadillColors.page)
|
|
}
|
|
}
|