Tip section: card design per user mockup

Three stacked rounded cards, one per tier, each with an accent-tinted
fuel-pump icon and price (Splash & Dash #64D2FF blue, Half a Tank
#30D158 green, Fill 'Er Up #FFD60A amber — the app's fuel palette),
name + blurb on the left, bold accent price on the right. Cards sit on
clear list rows with their own rounded fill + subtle accent tint.
Purchase flow, per-tier live prices, disabled state and footer copy
unchanged.
This commit is contained in:
FuelBoard Contributor
2026-08-16 08:57:40 +01:00
parent 5060aa9df5
commit 9fdcc7370e
+44 -18
View File
@@ -298,25 +298,47 @@ struct SettingsView: View {
}
Section {
ForEach(TipStore.tiers) { tier in
Button {
Task { await tipStore.purchase(tier) }
} label: {
HStack {
VStack(alignment: .leading, spacing: 2) {
Text(tier.name)
Text(tier.blurb)
.font(.caption)
.foregroundStyle(.secondary)
VStack(spacing: 10) {
ForEach(TipStore.tiers) { tier in
Button {
Task { await tipStore.purchase(tier) }
} label: {
HStack(spacing: 12) {
Image(systemName: "fuelpump.fill")
.font(.title3)
.foregroundStyle(tier.accent)
.frame(width: 34)
VStack(alignment: .leading, spacing: 2) {
Text(tier.name)
.font(.headline)
Text(tier.blurb)
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer(minLength: 8)
Text(tipStore.displayPrice(for: tier))
.font(.headline.weight(.bold))
.foregroundStyle(tier.accent)
.monospacedDigit()
}
Spacer()
Text(tipStore.displayPrice(for: tier))
.foregroundStyle(.secondary)
.monospacedDigit()
.padding(.horizontal, 14)
.padding(.vertical, 12)
.frame(maxWidth: .infinity, alignment: .leading)
.background(
RoundedRectangle(cornerRadius: 12)
.fill(Color(.secondarySystemGroupedBackground))
.overlay(
RoundedRectangle(cornerRadius: 12)
.fill(tier.accent.opacity(0.05))
)
)
}
.buttonStyle(.plain)
.disabled(tipStore.purchaseInProgress)
}
.disabled(tipStore.purchaseInProgress)
}
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
} header: {
Text("Support FuelBoard")
} footer: {
@@ -569,15 +591,19 @@ final class TipStore: ObservableObject {
let name: String
let blurb: String
let fallbackPrice: String
let accent: Color // card/price accent (matches the fuel palette)
}
static let tiers: [TipTier] = [
TipTier(id: "com.apt.fuelboard.tip099", name: "Splash & Dash",
blurb: "Just enough to keep things moving.", fallbackPrice: "£0.99"),
blurb: "Just enough to keep things moving.", fallbackPrice: "£0.99",
accent: Color(red: 0.39, green: 0.82, blue: 1.0)), // #64D2FF
TipTier(id: "com.apt.fuelboard.tip299", name: "Half a Tank",
blurb: "A generous top-up for development.", fallbackPrice: "£2.99"),
blurb: "A generous top-up for development.", fallbackPrice: "£2.99",
accent: Color(red: 0.19, green: 0.82, blue: 0.35)), // #30D158
TipTier(id: "com.apt.fuelboard.tip499", name: "Fill 'Er Up",
blurb: "Keeping the app on the road.", fallbackPrice: "£4.99"),
blurb: "Keeping the app on the road.", fallbackPrice: "£4.99",
accent: Color(red: 1.0, green: 0.84, blue: 0.04)), // #FFD60A
]
@Published private(set) var products: [String: Product] = [:]