├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Example
├── Example.xcodeproj
│ └── project.xcworkspace
│ │ └── xcshareddata
│ │ └── swiftpm
│ │ └── Package.resolved
├── SwiftUICardStack-Example.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── swiftpm
│ │ │ └── Package.resolved
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── Example.xcscheme
│ │ └── Tests.xcscheme
├── SwiftUICardStack-Example
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── ContentView.swift
│ ├── Demo Film
│ │ ├── GitHubBanner.png
│ │ ├── Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif
│ │ ├── Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif
│ │ └── Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png
│ ├── ExampleApp.swift
│ ├── GitHubBannerView.swift
│ ├── Info.plist
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ └── SwiftUICardStack-Example.entitlements
└── SwiftUICardStack-ExampleUITests
│ ├── Info.plist
│ ├── SwiftUICardStack_ExampleUITests.swift
│ └── __Snapshots__
│ └── SwiftUICardStack_ExampleUITests
│ └── testExample.1.png
├── LICENSE
├── Package.swift
├── README.md
└── Sources
└── SwiftUICardStack
├── CardStack.swift
├── CardStackSource.swift
├── Common.swift
└── SwiftUICardStackView.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | DerivedData/
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "SwiftUICardStack",
6 | "repositoryURL": "https://github.com/p-larson/SwiftUICardStack",
7 | "state": {
8 | "branch": "main",
9 | "revision": "85c78a060f33788da2932ed925affcb40d83d911",
10 | "version": null
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 9817D83626652E020043FBC5 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D539D32661C87F00ED29DC /* ContentView.swift */; };
11 | 9817D83726652E060043FBC5 /* GitHubBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 989AFA222664620800D6D1B6 /* GitHubBannerView.swift */; };
12 | 9817D83926652E510043FBC5 /* SwiftUICardStack in Frameworks */ = {isa = PBXBuildFile; productRef = 9817D83826652E510043FBC5 /* SwiftUICardStack */; };
13 | 9817D83B26652EFE0043FBC5 /* GitHubBanner.png in Resources */ = {isa = PBXBuildFile; fileRef = 9817D83A26652EFE0043FBC5 /* GitHubBanner.png */; };
14 | 989AFA212664611000D6D1B6 /* SwiftUICardStack in Frameworks */ = {isa = PBXBuildFile; productRef = 989AFA202664611000D6D1B6 /* SwiftUICardStack */; };
15 | 989AFA232664620800D6D1B6 /* GitHubBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 989AFA222664620800D6D1B6 /* GitHubBannerView.swift */; };
16 | 989AFA41266477B100D6D1B6 /* SwiftUICardStack_ExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 989AFA40266477B100D6D1B6 /* SwiftUICardStack_ExampleUITests.swift */; };
17 | 989AFA4A2664780E00D6D1B6 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 989AFA492664780E00D6D1B6 /* SnapshotTesting */; };
18 | 98D539D22661C87F00ED29DC /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D539D12661C87F00ED29DC /* ExampleApp.swift */; };
19 | 98D539D42661C87F00ED29DC /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D539D32661C87F00ED29DC /* ContentView.swift */; };
20 | 98D539D62661C88000ED29DC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D539D52661C88000ED29DC /* Assets.xcassets */; };
21 | 98D539D92661C88000ED29DC /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D539D82661C88000ED29DC /* Preview Assets.xcassets */; };
22 | 98D539E52661CDA100ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif in Resources */ = {isa = PBXBuildFile; fileRef = 98D539E42661CDA100ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif */; };
23 | 98D539E72661CDB300ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif in Resources */ = {isa = PBXBuildFile; fileRef = 98D539E62661CDB300ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif */; };
24 | 98D539E92661CDB900ED29DC /* Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png in Resources */ = {isa = PBXBuildFile; fileRef = 98D539E82661CDB900ED29DC /* Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXFileReference section */
28 | 9817D83A26652EFE0043FBC5 /* GitHubBanner.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = GitHubBanner.png; sourceTree = ""; };
29 | 989AFA222664620800D6D1B6 /* GitHubBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GitHubBannerView.swift; sourceTree = ""; };
30 | 989AFA2426646A8D00D6D1B6 /* SwiftUICardStack-Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SwiftUICardStack-Example.entitlements"; sourceTree = ""; };
31 | 989AFA3E266477B100D6D1B6 /* SwiftUICardStack-ExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftUICardStack-ExampleUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 989AFA40266477B100D6D1B6 /* SwiftUICardStack_ExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUICardStack_ExampleUITests.swift; sourceTree = ""; };
33 | 989AFA42266477B100D6D1B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | 98D539CE2661C87F00ED29DC /* SwiftUICardStack-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SwiftUICardStack-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
35 | 98D539D12661C87F00ED29DC /* ExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleApp.swift; sourceTree = ""; };
36 | 98D539D32661C87F00ED29DC /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
37 | 98D539D52661C88000ED29DC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
38 | 98D539D82661C88000ED29DC /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
39 | 98D539DA2661C88000ED29DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
40 | 98D539E42661CDA100ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif"; sourceTree = ""; };
41 | 98D539E62661CDB300ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif"; sourceTree = ""; };
42 | 98D539E82661CDB900ED29DC /* Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png"; sourceTree = ""; };
43 | /* End PBXFileReference section */
44 |
45 | /* Begin PBXFrameworksBuildPhase section */
46 | 989AFA3B266477B100D6D1B6 /* Frameworks */ = {
47 | isa = PBXFrameworksBuildPhase;
48 | buildActionMask = 2147483647;
49 | files = (
50 | 989AFA4A2664780E00D6D1B6 /* SnapshotTesting in Frameworks */,
51 | 9817D83926652E510043FBC5 /* SwiftUICardStack in Frameworks */,
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | 98D539CB2661C87F00ED29DC /* Frameworks */ = {
56 | isa = PBXFrameworksBuildPhase;
57 | buildActionMask = 2147483647;
58 | files = (
59 | 989AFA212664611000D6D1B6 /* SwiftUICardStack in Frameworks */,
60 | );
61 | runOnlyForDeploymentPostprocessing = 0;
62 | };
63 | /* End PBXFrameworksBuildPhase section */
64 |
65 | /* Begin PBXGroup section */
66 | 9817D82E26652AA30043FBC5 /* Frameworks */ = {
67 | isa = PBXGroup;
68 | children = (
69 | );
70 | name = Frameworks;
71 | sourceTree = "";
72 | };
73 | 989AFA3F266477B100D6D1B6 /* SwiftUICardStack-ExampleUITests */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 989AFA40266477B100D6D1B6 /* SwiftUICardStack_ExampleUITests.swift */,
77 | 989AFA42266477B100D6D1B6 /* Info.plist */,
78 | );
79 | path = "SwiftUICardStack-ExampleUITests";
80 | sourceTree = "";
81 | };
82 | 98D539C52661C87F00ED29DC = {
83 | isa = PBXGroup;
84 | children = (
85 | 98D539D02661C87F00ED29DC /* SwiftUICardStack-Example */,
86 | 989AFA3F266477B100D6D1B6 /* SwiftUICardStack-ExampleUITests */,
87 | 98D539CF2661C87F00ED29DC /* Products */,
88 | 9817D82E26652AA30043FBC5 /* Frameworks */,
89 | );
90 | sourceTree = "";
91 | };
92 | 98D539CF2661C87F00ED29DC /* Products */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 98D539CE2661C87F00ED29DC /* SwiftUICardStack-Example.app */,
96 | 989AFA3E266477B100D6D1B6 /* SwiftUICardStack-ExampleUITests.xctest */,
97 | );
98 | name = Products;
99 | sourceTree = "";
100 | };
101 | 98D539D02661C87F00ED29DC /* SwiftUICardStack-Example */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 989AFA2426646A8D00D6D1B6 /* SwiftUICardStack-Example.entitlements */,
105 | 98D539D12661C87F00ED29DC /* ExampleApp.swift */,
106 | 98D539D32661C87F00ED29DC /* ContentView.swift */,
107 | 989AFA222664620800D6D1B6 /* GitHubBannerView.swift */,
108 | 98D539D52661C88000ED29DC /* Assets.xcassets */,
109 | 98D539E32661CD9000ED29DC /* Demo Film */,
110 | 98D539DA2661C88000ED29DC /* Info.plist */,
111 | 98D539D72661C88000ED29DC /* Preview Content */,
112 | );
113 | path = "SwiftUICardStack-Example";
114 | sourceTree = "";
115 | };
116 | 98D539D72661C88000ED29DC /* Preview Content */ = {
117 | isa = PBXGroup;
118 | children = (
119 | 98D539D82661C88000ED29DC /* Preview Assets.xcassets */,
120 | );
121 | path = "Preview Content";
122 | sourceTree = "";
123 | };
124 | 98D539E32661CD9000ED29DC /* Demo Film */ = {
125 | isa = PBXGroup;
126 | children = (
127 | 9817D83A26652EFE0043FBC5 /* GitHubBanner.png */,
128 | 98D539E42661CDA100ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif */,
129 | 98D539E62661CDB300ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif */,
130 | 98D539E82661CDB900ED29DC /* Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png */,
131 | );
132 | path = "Demo Film";
133 | sourceTree = "";
134 | };
135 | /* End PBXGroup section */
136 |
137 | /* Begin PBXNativeTarget section */
138 | 989AFA3D266477B100D6D1B6 /* SwiftUICardStack-ExampleUITests */ = {
139 | isa = PBXNativeTarget;
140 | buildConfigurationList = 989AFA45266477B100D6D1B6 /* Build configuration list for PBXNativeTarget "SwiftUICardStack-ExampleUITests" */;
141 | buildPhases = (
142 | 989AFA3A266477B100D6D1B6 /* Sources */,
143 | 989AFA3B266477B100D6D1B6 /* Frameworks */,
144 | 989AFA3C266477B100D6D1B6 /* Resources */,
145 | );
146 | buildRules = (
147 | );
148 | dependencies = (
149 | 9817D83526652DC60043FBC5 /* PBXTargetDependency */,
150 | );
151 | name = "SwiftUICardStack-ExampleUITests";
152 | packageProductDependencies = (
153 | 989AFA492664780E00D6D1B6 /* SnapshotTesting */,
154 | 9817D83826652E510043FBC5 /* SwiftUICardStack */,
155 | );
156 | productName = "SwiftUICardStack-ExampleUITests";
157 | productReference = 989AFA3E266477B100D6D1B6 /* SwiftUICardStack-ExampleUITests.xctest */;
158 | productType = "com.apple.product-type.bundle.ui-testing";
159 | };
160 | 98D539CD2661C87F00ED29DC /* SwiftUICardStack-Example */ = {
161 | isa = PBXNativeTarget;
162 | buildConfigurationList = 98D539DD2661C88000ED29DC /* Build configuration list for PBXNativeTarget "SwiftUICardStack-Example" */;
163 | buildPhases = (
164 | 98D539CA2661C87F00ED29DC /* Sources */,
165 | 98D539CB2661C87F00ED29DC /* Frameworks */,
166 | 98D539CC2661C87F00ED29DC /* Resources */,
167 | );
168 | buildRules = (
169 | );
170 | dependencies = (
171 | );
172 | name = "SwiftUICardStack-Example";
173 | packageProductDependencies = (
174 | 989AFA202664611000D6D1B6 /* SwiftUICardStack */,
175 | );
176 | productName = Example;
177 | productReference = 98D539CE2661C87F00ED29DC /* SwiftUICardStack-Example.app */;
178 | productType = "com.apple.product-type.application";
179 | };
180 | /* End PBXNativeTarget section */
181 |
182 | /* Begin PBXProject section */
183 | 98D539C62661C87F00ED29DC /* Project object */ = {
184 | isa = PBXProject;
185 | attributes = {
186 | LastSwiftUpdateCheck = 1250;
187 | LastUpgradeCheck = 1250;
188 | TargetAttributes = {
189 | 989AFA3D266477B100D6D1B6 = {
190 | CreatedOnToolsVersion = 12.5;
191 | };
192 | 98D539CD2661C87F00ED29DC = {
193 | CreatedOnToolsVersion = 12.5;
194 | };
195 | };
196 | };
197 | buildConfigurationList = 98D539C92661C87F00ED29DC /* Build configuration list for PBXProject "SwiftUICardStack-Example" */;
198 | compatibilityVersion = "Xcode 9.3";
199 | developmentRegion = en;
200 | hasScannedForEncodings = 0;
201 | knownRegions = (
202 | en,
203 | Base,
204 | );
205 | mainGroup = 98D539C52661C87F00ED29DC;
206 | packageReferences = (
207 | 989AFA1F2664611000D6D1B6 /* XCRemoteSwiftPackageReference "SwiftUICardStack" */,
208 | 989AFA482664780E00D6D1B6 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
209 | );
210 | productRefGroup = 98D539CF2661C87F00ED29DC /* Products */;
211 | projectDirPath = "";
212 | projectRoot = "";
213 | targets = (
214 | 98D539CD2661C87F00ED29DC /* SwiftUICardStack-Example */,
215 | 989AFA3D266477B100D6D1B6 /* SwiftUICardStack-ExampleUITests */,
216 | );
217 | };
218 | /* End PBXProject section */
219 |
220 | /* Begin PBXResourcesBuildPhase section */
221 | 989AFA3C266477B100D6D1B6 /* Resources */ = {
222 | isa = PBXResourcesBuildPhase;
223 | buildActionMask = 2147483647;
224 | files = (
225 | );
226 | runOnlyForDeploymentPostprocessing = 0;
227 | };
228 | 98D539CC2661C87F00ED29DC /* Resources */ = {
229 | isa = PBXResourcesBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | 98D539E72661CDB300ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif in Resources */,
233 | 98D539E52661CDA100ED29DC /* Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif in Resources */,
234 | 98D539D92661C88000ED29DC /* Preview Assets.xcassets in Resources */,
235 | 98D539D62661C88000ED29DC /* Assets.xcassets in Resources */,
236 | 9817D83B26652EFE0043FBC5 /* GitHubBanner.png in Resources */,
237 | 98D539E92661CDB900ED29DC /* Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png in Resources */,
238 | );
239 | runOnlyForDeploymentPostprocessing = 0;
240 | };
241 | /* End PBXResourcesBuildPhase section */
242 |
243 | /* Begin PBXSourcesBuildPhase section */
244 | 989AFA3A266477B100D6D1B6 /* Sources */ = {
245 | isa = PBXSourcesBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | 9817D83626652E020043FBC5 /* ContentView.swift in Sources */,
249 | 989AFA41266477B100D6D1B6 /* SwiftUICardStack_ExampleUITests.swift in Sources */,
250 | 9817D83726652E060043FBC5 /* GitHubBannerView.swift in Sources */,
251 | );
252 | runOnlyForDeploymentPostprocessing = 0;
253 | };
254 | 98D539CA2661C87F00ED29DC /* Sources */ = {
255 | isa = PBXSourcesBuildPhase;
256 | buildActionMask = 2147483647;
257 | files = (
258 | 98D539D42661C87F00ED29DC /* ContentView.swift in Sources */,
259 | 989AFA232664620800D6D1B6 /* GitHubBannerView.swift in Sources */,
260 | 98D539D22661C87F00ED29DC /* ExampleApp.swift in Sources */,
261 | );
262 | runOnlyForDeploymentPostprocessing = 0;
263 | };
264 | /* End PBXSourcesBuildPhase section */
265 |
266 | /* Begin PBXTargetDependency section */
267 | 9817D83526652DC60043FBC5 /* PBXTargetDependency */ = {
268 | isa = PBXTargetDependency;
269 | productRef = 9817D83426652DC60043FBC5 /* SnapshotTesting */;
270 | };
271 | /* End PBXTargetDependency section */
272 |
273 | /* Begin XCBuildConfiguration section */
274 | 989AFA46266477B100D6D1B6 /* Debug */ = {
275 | isa = XCBuildConfiguration;
276 | buildSettings = {
277 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
278 | CODE_SIGN_STYLE = Automatic;
279 | DEVELOPMENT_TEAM = 8B8QZZ6VNV;
280 | INFOPLIST_FILE = "SwiftUICardStack-ExampleUITests/Info.plist";
281 | LD_RUNPATH_SEARCH_PATHS = (
282 | "$(inherited)",
283 | "@executable_path/Frameworks",
284 | "@loader_path/Frameworks",
285 | );
286 | PRODUCT_BUNDLE_IDENTIFIER = "software.larson.cardstack.SwiftUICardStack-ExampleUITests";
287 | PRODUCT_NAME = "$(TARGET_NAME)";
288 | PROVISIONING_PROFILE = "";
289 | SWIFT_VERSION = 5.0;
290 | TARGETED_DEVICE_FAMILY = "1,2";
291 | };
292 | name = Debug;
293 | };
294 | 989AFA47266477B100D6D1B6 /* Release */ = {
295 | isa = XCBuildConfiguration;
296 | buildSettings = {
297 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
298 | CODE_SIGN_STYLE = Automatic;
299 | DEVELOPMENT_TEAM = 8B8QZZ6VNV;
300 | INFOPLIST_FILE = "SwiftUICardStack-ExampleUITests/Info.plist";
301 | LD_RUNPATH_SEARCH_PATHS = (
302 | "$(inherited)",
303 | "@executable_path/Frameworks",
304 | "@loader_path/Frameworks",
305 | );
306 | PRODUCT_BUNDLE_IDENTIFIER = "software.larson.cardstack.SwiftUICardStack-ExampleUITests";
307 | PRODUCT_NAME = "$(TARGET_NAME)";
308 | PROVISIONING_PROFILE = "";
309 | SWIFT_VERSION = 5.0;
310 | TARGETED_DEVICE_FAMILY = "1,2";
311 | };
312 | name = Release;
313 | };
314 | 98D539DB2661C88000ED29DC /* Debug */ = {
315 | isa = XCBuildConfiguration;
316 | buildSettings = {
317 | ALWAYS_SEARCH_USER_PATHS = NO;
318 | CLANG_ANALYZER_NONNULL = YES;
319 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
321 | CLANG_CXX_LIBRARY = "libc++";
322 | CLANG_ENABLE_MODULES = YES;
323 | CLANG_ENABLE_OBJC_ARC = YES;
324 | CLANG_ENABLE_OBJC_WEAK = YES;
325 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
326 | CLANG_WARN_BOOL_CONVERSION = YES;
327 | CLANG_WARN_COMMA = YES;
328 | CLANG_WARN_CONSTANT_CONVERSION = YES;
329 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
330 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
331 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
332 | CLANG_WARN_EMPTY_BODY = YES;
333 | CLANG_WARN_ENUM_CONVERSION = YES;
334 | CLANG_WARN_INFINITE_RECURSION = YES;
335 | CLANG_WARN_INT_CONVERSION = YES;
336 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
337 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
338 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
339 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
340 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
341 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
342 | CLANG_WARN_STRICT_PROTOTYPES = YES;
343 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
344 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
345 | CLANG_WARN_UNREACHABLE_CODE = YES;
346 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
347 | COPY_PHASE_STRIP = NO;
348 | DEBUG_INFORMATION_FORMAT = dwarf;
349 | ENABLE_STRICT_OBJC_MSGSEND = YES;
350 | ENABLE_TESTABILITY = YES;
351 | GCC_C_LANGUAGE_STANDARD = gnu11;
352 | GCC_DYNAMIC_NO_PIC = NO;
353 | GCC_NO_COMMON_BLOCKS = YES;
354 | GCC_OPTIMIZATION_LEVEL = 0;
355 | GCC_PREPROCESSOR_DEFINITIONS = (
356 | "DEBUG=1",
357 | "$(inherited)",
358 | );
359 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
360 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
361 | GCC_WARN_UNDECLARED_SELECTOR = YES;
362 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
363 | GCC_WARN_UNUSED_FUNCTION = YES;
364 | GCC_WARN_UNUSED_VARIABLE = YES;
365 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
366 | MACOSX_DEPLOYMENT_TARGET = 11.0;
367 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
368 | MTL_FAST_MATH = YES;
369 | ONLY_ACTIVE_ARCH = YES;
370 | SDKROOT = iphoneos;
371 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
372 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
373 | };
374 | name = Debug;
375 | };
376 | 98D539DC2661C88000ED29DC /* Release */ = {
377 | isa = XCBuildConfiguration;
378 | buildSettings = {
379 | ALWAYS_SEARCH_USER_PATHS = NO;
380 | CLANG_ANALYZER_NONNULL = YES;
381 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
382 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
383 | CLANG_CXX_LIBRARY = "libc++";
384 | CLANG_ENABLE_MODULES = YES;
385 | CLANG_ENABLE_OBJC_ARC = YES;
386 | CLANG_ENABLE_OBJC_WEAK = YES;
387 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
388 | CLANG_WARN_BOOL_CONVERSION = YES;
389 | CLANG_WARN_COMMA = YES;
390 | CLANG_WARN_CONSTANT_CONVERSION = YES;
391 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
392 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
393 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
394 | CLANG_WARN_EMPTY_BODY = YES;
395 | CLANG_WARN_ENUM_CONVERSION = YES;
396 | CLANG_WARN_INFINITE_RECURSION = YES;
397 | CLANG_WARN_INT_CONVERSION = YES;
398 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
399 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
400 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
401 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
402 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
403 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
404 | CLANG_WARN_STRICT_PROTOTYPES = YES;
405 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
406 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
407 | CLANG_WARN_UNREACHABLE_CODE = YES;
408 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
409 | COPY_PHASE_STRIP = NO;
410 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
411 | ENABLE_NS_ASSERTIONS = NO;
412 | ENABLE_STRICT_OBJC_MSGSEND = YES;
413 | GCC_C_LANGUAGE_STANDARD = gnu11;
414 | GCC_NO_COMMON_BLOCKS = YES;
415 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
416 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
417 | GCC_WARN_UNDECLARED_SELECTOR = YES;
418 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
419 | GCC_WARN_UNUSED_FUNCTION = YES;
420 | GCC_WARN_UNUSED_VARIABLE = YES;
421 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
422 | MACOSX_DEPLOYMENT_TARGET = 11.0;
423 | MTL_ENABLE_DEBUG_INFO = NO;
424 | MTL_FAST_MATH = YES;
425 | SDKROOT = iphoneos;
426 | SWIFT_COMPILATION_MODE = wholemodule;
427 | SWIFT_OPTIMIZATION_LEVEL = "-O";
428 | VALIDATE_PRODUCT = YES;
429 | };
430 | name = Release;
431 | };
432 | 98D539DE2661C88000ED29DC /* Debug */ = {
433 | isa = XCBuildConfiguration;
434 | buildSettings = {
435 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
436 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
437 | CODE_SIGN_ENTITLEMENTS = "SwiftUICardStack-Example/SwiftUICardStack-Example.entitlements";
438 | CODE_SIGN_STYLE = Automatic;
439 | DEVELOPMENT_ASSET_PATHS = "\"SwiftUICardStack-Example/Preview Content\"";
440 | DEVELOPMENT_TEAM = 8B8QZZ6VNV;
441 | ENABLE_PREVIEWS = YES;
442 | INFOPLIST_FILE = "SwiftUICardStack-Example/Info.plist";
443 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
444 | LD_RUNPATH_SEARCH_PATHS = (
445 | "$(inherited)",
446 | "@executable_path/Frameworks",
447 | );
448 | PRODUCT_BUNDLE_IDENTIFIER = software.larson.cardstack.Example;
449 | PRODUCT_NAME = "$(TARGET_NAME)";
450 | SUPPORTS_MACCATALYST = YES;
451 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
452 | SWIFT_VERSION = 5.0;
453 | TARGETED_DEVICE_FAMILY = "1,2,6";
454 | };
455 | name = Debug;
456 | };
457 | 98D539DF2661C88000ED29DC /* Release */ = {
458 | isa = XCBuildConfiguration;
459 | buildSettings = {
460 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
461 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
462 | CODE_SIGN_ENTITLEMENTS = "SwiftUICardStack-Example/SwiftUICardStack-Example.entitlements";
463 | CODE_SIGN_STYLE = Automatic;
464 | DEVELOPMENT_ASSET_PATHS = "\"SwiftUICardStack-Example/Preview Content\"";
465 | DEVELOPMENT_TEAM = 8B8QZZ6VNV;
466 | ENABLE_PREVIEWS = YES;
467 | INFOPLIST_FILE = "SwiftUICardStack-Example/Info.plist";
468 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
469 | LD_RUNPATH_SEARCH_PATHS = (
470 | "$(inherited)",
471 | "@executable_path/Frameworks",
472 | );
473 | PRODUCT_BUNDLE_IDENTIFIER = software.larson.cardstack.Example;
474 | PRODUCT_NAME = "$(TARGET_NAME)";
475 | SUPPORTS_MACCATALYST = YES;
476 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
477 | SWIFT_VERSION = 5.0;
478 | TARGETED_DEVICE_FAMILY = "1,2,6";
479 | };
480 | name = Release;
481 | };
482 | /* End XCBuildConfiguration section */
483 |
484 | /* Begin XCConfigurationList section */
485 | 989AFA45266477B100D6D1B6 /* Build configuration list for PBXNativeTarget "SwiftUICardStack-ExampleUITests" */ = {
486 | isa = XCConfigurationList;
487 | buildConfigurations = (
488 | 989AFA46266477B100D6D1B6 /* Debug */,
489 | 989AFA47266477B100D6D1B6 /* Release */,
490 | );
491 | defaultConfigurationIsVisible = 0;
492 | defaultConfigurationName = Release;
493 | };
494 | 98D539C92661C87F00ED29DC /* Build configuration list for PBXProject "SwiftUICardStack-Example" */ = {
495 | isa = XCConfigurationList;
496 | buildConfigurations = (
497 | 98D539DB2661C88000ED29DC /* Debug */,
498 | 98D539DC2661C88000ED29DC /* Release */,
499 | );
500 | defaultConfigurationIsVisible = 0;
501 | defaultConfigurationName = Release;
502 | };
503 | 98D539DD2661C88000ED29DC /* Build configuration list for PBXNativeTarget "SwiftUICardStack-Example" */ = {
504 | isa = XCConfigurationList;
505 | buildConfigurations = (
506 | 98D539DE2661C88000ED29DC /* Debug */,
507 | 98D539DF2661C88000ED29DC /* Release */,
508 | );
509 | defaultConfigurationIsVisible = 0;
510 | defaultConfigurationName = Release;
511 | };
512 | /* End XCConfigurationList section */
513 |
514 | /* Begin XCRemoteSwiftPackageReference section */
515 | 989AFA1F2664611000D6D1B6 /* XCRemoteSwiftPackageReference "SwiftUICardStack" */ = {
516 | isa = XCRemoteSwiftPackageReference;
517 | repositoryURL = "https://github.com/p-larson/SwiftUICardStack";
518 | requirement = {
519 | kind = upToNextMajorVersion;
520 | minimumVersion = 1.0.0;
521 | };
522 | };
523 | 989AFA482664780E00D6D1B6 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = {
524 | isa = XCRemoteSwiftPackageReference;
525 | repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing";
526 | requirement = {
527 | kind = upToNextMajorVersion;
528 | minimumVersion = 1.9.0;
529 | };
530 | };
531 | /* End XCRemoteSwiftPackageReference section */
532 |
533 | /* Begin XCSwiftPackageProductDependency section */
534 | 9817D83426652DC60043FBC5 /* SnapshotTesting */ = {
535 | isa = XCSwiftPackageProductDependency;
536 | package = 989AFA482664780E00D6D1B6 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */;
537 | productName = SnapshotTesting;
538 | };
539 | 9817D83826652E510043FBC5 /* SwiftUICardStack */ = {
540 | isa = XCSwiftPackageProductDependency;
541 | package = 989AFA1F2664611000D6D1B6 /* XCRemoteSwiftPackageReference "SwiftUICardStack" */;
542 | productName = SwiftUICardStack;
543 | };
544 | 989AFA202664611000D6D1B6 /* SwiftUICardStack */ = {
545 | isa = XCSwiftPackageProductDependency;
546 | package = 989AFA1F2664611000D6D1B6 /* XCRemoteSwiftPackageReference "SwiftUICardStack" */;
547 | productName = SwiftUICardStack;
548 | };
549 | 989AFA492664780E00D6D1B6 /* SnapshotTesting */ = {
550 | isa = XCSwiftPackageProductDependency;
551 | package = 989AFA482664780E00D6D1B6 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */;
552 | productName = SnapshotTesting;
553 | };
554 | /* End XCSwiftPackageProductDependency section */
555 | };
556 | rootObject = 98D539C62661C87F00ED29DC /* Project object */;
557 | }
558 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "SnapshotTesting",
6 | "repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing",
7 | "state": {
8 | "branch": null,
9 | "revision": "f8a9c997c3c1dab4e216a8ec9014e23144cbab37",
10 | "version": "1.9.0"
11 | }
12 | },
13 | {
14 | "package": "SwiftUICardStack",
15 | "repositoryURL": "https://github.com/p-larson/SwiftUICardStack",
16 | "state": {
17 | "branch": null,
18 | "revision": "edbbc8fc619deeb902d62d37f5e4241cca8aee14",
19 | "version": "1.0.0"
20 | }
21 | }
22 | ]
23 | },
24 | "version": 1
25 | }
26 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Example
4 | //
5 | // Created by Peter Larson on 5/28/21.
6 | //
7 |
8 | import SwiftUI
9 | import SwiftUICardStack
10 |
11 | // MARK: Previews
12 |
13 | // Mock Card Model
14 |
15 | struct CardTheme: Equatable, Hashable {
16 | let primary, secondary: UIColor
17 | }
18 |
19 | extension CardTheme {
20 | static let executive = CardTheme(primary: #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1), secondary: #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1))
21 | static let travel = CardTheme(primary: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1), secondary: #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1))
22 | static let gift = CardTheme(primary: #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1), secondary: #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1))
23 | static let food = CardTheme(primary: #colorLiteral(red: 0.9411764741, green: 0.4980392158, blue: 0.3529411852, alpha: 1), secondary: #colorLiteral(red: 0.9568627477, green: 0.6588235497, blue: 0.5450980663, alpha: 1))
24 | }
25 |
26 |
27 | struct CardModel: Equatable, Identifiable, Hashable {
28 | let name: String
29 | let number: UInt
30 | let theme: CardTheme
31 | let id = UUID()
32 | }
33 |
34 | let mock = [
35 | CardModel(name: "Executive Card", number: 1234567812345678, theme: .executive),
36 | CardModel(name: "Travel Card", number: 1234567812345678, theme: .travel),
37 | CardModel(name: "Gift Card", number: 1234567812345678, theme: .gift),
38 | CardModel(name: "Food Card", number: 1234567812345678, theme: .food)
39 | ]
40 |
41 | struct CardView: View {
42 | let model: CardModel
43 | let id = UUID()
44 |
45 | var body: some View {
46 | ZStack {
47 | RoundedRectangle(cornerRadius: 25.0, style: .continuous)
48 | .fill(
49 | LinearGradient(
50 | gradient: Gradient(colors: [Color(model.theme.primary), Color(model.theme.secondary)]),
51 | startPoint: .bottom,
52 | endPoint: .top
53 | )
54 | )
55 |
56 | VStack {
57 | HStack {
58 | Text(model.name.uppercased())
59 | .font(
60 | .system(size: 20, weight: .regular, design: .monospaced)
61 | )
62 | Spacer()
63 | Text("LARSON")
64 | .font(.system(.callout, design: .monospaced))
65 | .blendMode(.luminosity)
66 | .foregroundColor(.white)
67 | .opacity(1/2)
68 | }
69 | Spacer()
70 | HStack(spacing: 0) {
71 | Text(model.number.description)
72 | .font(
73 | .system(size: 16, weight: .bold, design: .rounded)
74 | )
75 | .kerning(1.5)
76 | Spacer()
77 | Circle()
78 | .strokeBorder(lineWidth: 1.5)
79 | .frame(width: 30, height: 30)
80 | .offset(x: 15)
81 | Circle()
82 | .strokeBorder(lineWidth: 1.5)
83 | .frame(width: 30, height: 30)
84 | }
85 | }
86 | .foregroundColor(.white)
87 | .padding(20)
88 | }
89 | .frame(height: 200)
90 | }
91 | }
92 |
93 |
94 | func cardDetail(for item: CardModel) -> some View {
95 | VStack {
96 | Text("Details")
97 | .font(.title2)
98 | CardView(model: item)
99 | }
100 | .padding(.horizontal, 20)
101 | }
102 |
103 | struct CardStackDemoView: View {
104 | @State var selected: CardModel? = nil
105 |
106 | var body: some View {
107 | GeometryReader { geometry in
108 | ScrollView {
109 | VStack {
110 | Text("SwiftUICardStack Example")
111 | .font(.title)
112 | // The magic
113 | CardStack(
114 | // Data
115 | items: mock,
116 | // Triggered when User gestures a detail inspection of a item.
117 | selection: $selected,
118 | // View representation for Data.
119 | builder: CardView.init(model:)
120 | )
121 |
122 | Text("plarson/SwiftUICardStack")
123 | .font(.caption)
124 | Spacer()
125 | }
126 | .padding()
127 | .frame(
128 | width: geometry.size.width,
129 | height: geometry.size.height
130 | )
131 | }
132 | }
133 | // Detail View for Selected Item, triggered by CardStack#showDetail
134 | .sheet(item: $selected) { item in
135 | VStack(alignment: .leading) {
136 | HStack {
137 | Text("Some Detail View:")
138 | .font(.title2)
139 | Spacer()
140 | }
141 | HStack {
142 | Text(item.name.description)
143 | .font(.footnote)
144 | .italic()
145 | Spacer()
146 | }
147 | CardView(model: item)
148 | }
149 | .padding(20)
150 | }
151 | }
152 | }
153 |
154 | struct CardStackPreviews: PreviewProvider {
155 | static var previews: some View {
156 | CardStackDemoView()
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Demo Film/GitHubBanner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p-larson/SwiftUICardStack/6560303d10438e029c5f7281be2224eb8c475dab/Example/SwiftUICardStack-Example/Demo Film/GitHubBanner.png
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Demo Film/Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p-larson/SwiftUICardStack/6560303d10438e029c5f7281be2224eb8c475dab/Example/SwiftUICardStack-Example/Demo Film/Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.27.gif
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Demo Film/Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p-larson/SwiftUICardStack/6560303d10438e029c5f7281be2224eb8c475dab/Example/SwiftUICardStack-Example/Demo Film/Simulator Screen Recording - iPhone 12 - 2021-05-28 at 19.37.49.gif
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Demo Film/Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p-larson/SwiftUICardStack/6560303d10438e029c5f7281be2224eb8c475dab/Example/SwiftUICardStack-Example/Demo Film/Simulator Screen Shot - iPhone 12 - 2021-05-28 at 19.36.28.png
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/ExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleApp.swift
3 | // Example
4 | //
5 | // Created by Peter Larson on 5/28/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct ExampleApp: App {
12 | var body: some Scene {
13 | #if DEBUG
14 | WindowGroup {
15 | GitHubBanner_Previews.previews
16 | }
17 | #else
18 | WindowGroup {
19 | CardStackDemoView()
20 | }
21 | #endif
22 |
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/GitHubBannerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GitHubSocialPreview.swift
3 | // SwiftUICardStack-Example
4 | //
5 | // Created by Peter Larson on 5/30/21.
6 | //
7 |
8 | import SwiftUI
9 | import SwiftUICardStack
10 |
11 | // 1280×640
12 |
13 | struct GitHubBannerView: View {
14 | var body: some View {
15 | ZStack {
16 | VStack {
17 | VStack {
18 | Text("🗂SwiftUIStackView")
19 | .font(.system(size: 48, weight: .regular, design: .default))
20 |
21 | Text("A interactive way to peek and sort through a collection")
22 | .font(.system(size: 20, weight: .semibold, design: .rounded))
23 | }
24 |
25 | CardStack(
26 | // Data
27 | items: mock,
28 | // Triggered when User gestures a detail inspection of a item.
29 | selection: .constant(nil),
30 | // View representation for Data.
31 | builder: CardView.init(model:)
32 | )
33 | .frame(width: 400)
34 | .redacted(reason: .placeholder)
35 | }
36 | HStack {
37 | Spacer()
38 | VStack {
39 | Spacer()
40 | Text("@p-larson")
41 | }
42 | }
43 | .padding()
44 | }
45 | }
46 | }
47 |
48 | public struct GitHubBanner_Previews: PreviewProvider {
49 | public static var previews: some View {
50 | GitHubBannerView()
51 | .previewLayout(.fixed(width: 1280, height: 640))
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 |
28 | UIApplicationSupportsIndirectInputEvents
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-Example/SwiftUICardStack-Example.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.assets.movies.read-write
8 |
9 | com.apple.security.assets.music.read-write
10 |
11 | com.apple.security.assets.pictures.read-write
12 |
13 | com.apple.security.files.downloads.read-write
14 |
15 | com.apple.security.files.user-selected.read-write
16 |
17 | com.apple.security.network.client
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-ExampleUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-ExampleUITests/SwiftUICardStack_ExampleUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUICardStack_ExampleUITests.swift
3 | // SwiftUICardStack-ExampleUITests
4 | //
5 | // Created by Peter Larson on 5/30/21.
6 | //
7 |
8 | import XCTest
9 | import SwiftUICardStack
10 | import SnapshotTesting
11 |
12 | class SwiftUICardStack_ExampleUITests: XCTestCase {
13 |
14 | // Generates a snapshot of the view @1280x640 png
15 | func testGitHubSocialPreview() throws {
16 |
17 | let view = GitHubBanner_Previews
18 | .previews
19 | .frame(width: 1280, height: 640)
20 |
21 | assertSnapshot(matching: view, as: .image)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Example/SwiftUICardStack-ExampleUITests/__Snapshots__/SwiftUICardStack_ExampleUITests/testExample.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p-larson/SwiftUICardStack/6560303d10438e029c5f7281be2224eb8c475dab/Example/SwiftUICardStack-ExampleUITests/__Snapshots__/SwiftUICardStack_ExampleUITests/testExample.1.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Peter Larson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "SwiftUICardStack",
8 | platforms: [
9 | .macOS(.v10_12),
10 | .iOS(.v13),
11 | .tvOS(.v14)
12 | ],
13 | products: [
14 | .library(
15 | name: "SwiftUICardStack",
16 | targets: ["SwiftUICardStack"]
17 | ),
18 | ],
19 | targets: [
20 | .target(
21 | name: "SwiftUICardStack",
22 | dependencies: []
23 | ),
24 | ]
25 | )
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🗂 SwiftUICardStack
2 |
3 |
4 |
5 |
6 |
7 | Create an *easy to peek* SwiftUI View to showcase your own data, catalog, images, or anything you'd like.
8 |
9 | ## Contents
10 |
11 | - [🔭 Supported Platforms](#supported-platforms)
12 | - [📦 Package](#package)
13 | - [🔨 Example](#usage)
14 | - [🧨 Extra](#extra)
15 |
16 | ## Supported Platforms
17 |
18 | You can use the `CardStack` SwiftUI view in the following platforms:
19 |
20 | - macOS 10.12+ 🖥
21 | - iOS 14.0+ 📱
22 | - tvOS 14.0+ 📺
23 |
24 | ## Package
25 |
26 | ### For your XCode Package
27 |
28 | File > Swift Packages > Add Package Dependency: [https://github.com/p-larson/SwiftUICardStack](url)
29 |
30 | Select `main` branch then click `done`.
31 |
32 | ### For Swift Packages
33 |
34 | Add a dependency in your `Package.swift`
35 |
36 |
37 | ```swift
38 | .package(url: "https://github.com/p-larson/SwiftUICardStack", branch: "main")
39 | ```
40 |
41 | ## Usage
42 |
43 | ### Simple example
44 |
45 | ```swift
46 | CardStack(
47 | items: cards,
48 | selection: $selectedCard,
49 | builder: CardView.init(model:)
50 | )
51 | .sheet(item: $selectedCard) { card in
52 | VStack {
53 | Text(card.name)
54 | Text(card.description)
55 | Text(card.id)
56 | Text(card.someMoreDetailedInformation())
57 | }
58 | }
59 | ```
60 |
61 | See Full Example Usage @ [SwiftUICardStack/Example](/Example/SwiftUICardStack-Example)
62 |
63 | ## Extra
64 |
65 | ### My Favorite Line of Code from the Package 💕
66 |
67 | Line 17 of [Sources/SwiftUICardStack/CardStackSource.swift](/Sources/SwiftUICardStack/CardStackSource.swift)
68 |
69 | ```swift
70 | private(set) lazy var views: Array = items.map(builder).map(\.eraseToAnyView)
71 | ```
72 |
73 | **Why this is my favorite**
74 |
75 | *I use the power of KeyPaths to type erase the data set in a short and sweet one liner!*
76 |
77 | See [View#eraseToAnyView](/Sources/SwiftUICardStack/Common.swift)
78 |
79 | ### License
80 |
81 | Open Source [MIT License](https://github.com/p-larson/SwiftUICardStack/blob/main/LICENSE), aka: use how you please 😎
82 |
--------------------------------------------------------------------------------
/Sources/SwiftUICardStack/CardStack.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardStack.swift
3 | // SwiftUICardStack
4 | //
5 | // Created by Peter Larson on 5/28/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | // MARK: SwiftUICardStackView
11 |
12 | @available(iOS 13.0, *)
13 | public struct CardStack- : View where Item: Identifiable, ItemView: View {
14 |
15 | @ObservedObject var source: CardStackSource
-
16 |
17 | // MARK: Constants
18 |
19 | let maxItemsDisplayed: Int = 4
20 | let scaleDecrement: CGFloat = 0.05
21 | let verticalSpacing: CGFloat = 20.0
22 | let expandedVerticalSpacing: CGFloat = 100.0
23 | let animationSpeedLag: Double = 0.1
24 | let minimumAnimationSpeed: Double = 0.1
25 |
26 | // MARK: State
27 |
28 | @State var isStacked = true
29 | @Binding var selection: Item?
30 |
31 | // MARK: Init
32 |
33 | public init(
34 | items: [Item],
35 | selection: Binding
- ,
36 | builder: @escaping (Item) -> ItemView
37 | ) {
38 | self._selection = selection
39 | self._source = ObservedObject(
40 | wrappedValue: CardStackSource
- (
41 | items: items,
42 | builder: builder
43 | )
44 | )
45 | }
46 |
47 | public var body: some View {
48 | ZStack {
49 | ForEach(source.items.indices, content: build)
50 | }
51 | .padding(.top, isStacked ? verticalSpacing * CGFloat(maxItemsDisplayed - 1) : expandedVerticalSpacing * CGFloat(source.items.count - 1))
52 | .frame(
53 | maxWidth: isStacked ? nil : .infinity,
54 | maxHeight: isStacked ? nil : .infinity
55 | )
56 | .eraseToAnyView
57 | }
58 |
59 |
60 | // MARK: Content
61 |
62 | func build(index: Int) -> AnyView {
63 | let item = source.items[index]
64 | let view: AnyView = source.views[index]
65 |
66 | // Variables
67 | let yOffset: CGFloat = (isStacked ? verticalSpacing : expandedVerticalSpacing) * CGFloat(-index)
68 |
69 | return view
70 | .rotation3DEffect(
71 | isStacked ? .zero : .radians(.pi / 9),
72 | axis: (x: -1.0, y: 0.0, z: 0.0),
73 | anchor: .top,
74 | perspective: 1
75 | )
76 | .scaleEffect(isStacked ? 1.0 - (scaleDecrement * CGFloat(index)) : 1)
77 | .offset(y: yOffset)
78 | .zIndex(Double(source.items.count-index))
79 | .opacity(isStacked ? (!(index < maxItemsDisplayed) ? 0 : 1) : 1)
80 | .shadow(radius: 5)
81 | .onTapGesture {
82 | withAnimation(Animation.spring().speed(2)) {
83 | isStacked.toggle()
84 | }
85 | }
86 | .onLongPressGesture {
87 | selection = item
88 | }
89 | .eraseToAnyView
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Sources/SwiftUICardStack/CardStackSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardStackSource.swift
3 | // SwiftUICardStack
4 | //
5 | // Created by Peter Larson on 5/28/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @available(iOS 13.0, *)
11 | class CardStackSource
- : ObservableObject where ItemView: View {
12 | // Constants
13 | let builder: (Item) -> ItemView
14 | // Data
15 | private(set) var items: Array
-
16 | // The Power of Keypaths:
17 | private(set) lazy var views: Array = items.map(builder).map(\.eraseToAnyView)
18 |
19 | public init(
20 | items: Array
- ,
21 | builder: @escaping (Item) -> ItemView
22 | ) {
23 | self.items = items
24 | self.builder = builder
25 | }
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/Sources/SwiftUICardStack/Common.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Common.swift
3 | // SwiftUICardStack
4 | //
5 | // Created by Peter Larson on 5/28/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @available(iOS 13.0, *)
11 | extension View {
12 | // For KeyPaths and easier compiling, less type guessing and more assuming.
13 | var eraseToAnyView: AnyView {
14 | return AnyView(self)
15 | }
16 | }
17 |
18 | extension CGFloat {
19 | func capped(by range: ClosedRange) -> CGFloat {
20 | guard !range.contains(self) else {
21 | return self
22 | }
23 |
24 | return self < range.lowerBound ? range.lowerBound : range.upperBound
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/SwiftUICardStack/SwiftUICardStackView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUICardStackView.swift
3 | // SwiftUICardStack
4 | //
5 | // Created by Peter Larson on 5/25/21.
6 | //
7 | // Inspired by Saptarshi Prakash
8 | // https://www.youtube.com/watch?v=XPQxoAgTRtM
9 | //
10 | // MARK: Typealias'
11 | @available(iOS 13.0, *)
12 | typealias SwiftUICardStack = CardStack
13 | typealias PeterLarson = Any
14 |
15 |
--------------------------------------------------------------------------------