Skip to content

Commit b690eb7

Browse files
committed
Add a product USP struct with label views
1 parent 5285e58 commit b690eb7

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//
2+
// ProductUsp+Label.swift
3+
// KankodaKit
4+
//
5+
// Created by Daniel Saidi on 2024-12-04.
6+
// Copyright © 2024 Kankoda. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
public extension ProductUsp {
12+
13+
/// This label can be used to display a ``ProductUsp``.
14+
struct Label: View {
15+
16+
public init(_ usp: ProductUsp) {
17+
self.usp = usp
18+
}
19+
20+
private let usp: ProductUsp
21+
22+
public var body: some View {
23+
SwiftUI.Label(
24+
title: {
25+
VStack(alignment: .leading, spacing: 5) {
26+
Text(usp.title)
27+
.font(.headline)
28+
Text(usp.text)
29+
.fixedSize(horizontal: false, vertical: true)
30+
}
31+
},
32+
icon: {
33+
icon("house")
34+
.opacity(0)
35+
.overlay(icon(usp.iconName))
36+
}
37+
)
38+
}
39+
}
40+
41+
/// This stack can display a list of ``ProductUsp``s.
42+
struct LabelStack: View {
43+
44+
public init(_ usps: [ProductUsp]) {
45+
self.usps = usps
46+
}
47+
48+
private let usps: [ProductUsp]
49+
50+
public var body: some View {
51+
VStack(alignment: .leading, spacing: 20) {
52+
ForEach(Array(usps.enumerated()), id: \.offset) {
53+
ProductUsp.Label($0.element)
54+
}
55+
}
56+
.multilineTextAlignment(.leading)
57+
.frame(maxWidth: .infinity, alignment: .leading)
58+
}
59+
}
60+
}
61+
62+
private extension ProductUsp.Label {
63+
64+
func icon(
65+
_ name: String
66+
) -> some View {
67+
Image(systemName: name)
68+
.font(.headline)
69+
}
70+
}
71+
72+
#Preview {
73+
74+
let usp1 = ProductUsp(
75+
title: "Short title",
76+
text: "Pretty long text to see how it handles line breaks.",
77+
iconName: "person"
78+
)
79+
80+
let usp2 = ProductUsp(
81+
title: "A little longer title",
82+
text: "A short text.",
83+
iconName: "house"
84+
)
85+
86+
return VStack(alignment: .leading, spacing: 20) {
87+
ProductUsp.Label(usp1)
88+
ProductUsp.Label(usp2)
89+
}
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// ProductUsp.swift
3+
// KankodaKit
4+
//
5+
// Created by Daniel Saidi on 2024-12-04.
6+
// Copyright © 2024 Kankoda. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
/// This type defines a "unique selling point" for a product.
12+
///
13+
/// A USP is a way to specify a list of reasons why a person
14+
/// should purchase your product.
15+
///
16+
/// A USP can be rendered with a ``ProductUsp/Label`` and an
17+
/// array of USPs with a ``ProductUsp/LabelStack``.
18+
public struct ProductUsp {
19+
20+
/// Create a custom USP.
21+
///
22+
/// - Parameters:
23+
/// - title: The localized USP title.
24+
/// - text: The localized USP description text.
25+
/// - iconName: The SF Symbol name for the USP.
26+
public init(
27+
title: LocalizedStringKey,
28+
text: LocalizedStringKey,
29+
iconName: String
30+
) {
31+
self.title = title
32+
self.text = text
33+
self.iconName = iconName
34+
}
35+
36+
/// The localized USP title.
37+
public let title: LocalizedStringKey
38+
39+
/// The localized USP description text.
40+
public let text: LocalizedStringKey
41+
42+
/// The SF Symbol name for the USP.
43+
public let iconName: String
44+
}

Sources/StoreKitPlus/StoreKitPlus.docc/StoreKitPlus.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ StoreKitPlus is available under the MIT license.
5959

6060
- ``ProductID``
6161
- ``ProductRepresentable``
62+
- ``ProductUsp``
6263
- ``BasicProduct``
6364

6465
### Transactions

0 commit comments

Comments
 (0)