-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #239 from klaviyo/ab/CHNL-14651/add-klaviyo-form-p…
…review [CHNL-14651] add Klaviyo form preview
- Loading branch information
Showing
8 changed files
with
433 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
Sources/KlaviyoUI/KlaviyoWebView/Development Assets/HTML/jstest.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, viewport-fit=cover"/> | ||
<style> | ||
* { | ||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | ||
margin: 0; | ||
padding: 0; | ||
box-sizing: border-box; | ||
} | ||
|
||
body { | ||
margin: 0; | ||
padding: 0; | ||
background-color: rgba(0, 0, 0, 0.5); /* Translucent background */ | ||
display: flex; | ||
align-items: start; | ||
justify-content: center; | ||
height: 100vh; /* Full height */ | ||
overflow: hidden; /* Prevent scrolling */ | ||
padding-top: env(safe-area-inset-top); | ||
padding-right: env(safe-area-inset-right); | ||
padding-bottom: env(safe-area-inset-bottom); | ||
padding-left: env(safe-area-inset-left); | ||
} | ||
|
||
.content-container { | ||
background: white; | ||
border-radius: 16px; | ||
box-shadow: 0 12px 12px rgba(0, 0, 0, 0.4); | ||
width: 90%; | ||
max-width: 500px; /* Limit the content width */ | ||
overflow: auto; /* Enable scrolling */ | ||
padding: 24px; | ||
max-height: 100%; /* Prevent it from exceeding the viewport */ | ||
} | ||
|
||
.title { | ||
margin-bottom: 16px; | ||
} | ||
|
||
.section { | ||
background: white; | ||
border-radius: 8px; | ||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); | ||
margin-bottom: 16px; | ||
overflow: hidden; | ||
} | ||
|
||
.section-title { | ||
font-size: 16px; | ||
font-weight: bold; | ||
padding: 12px; | ||
background-color: #f0f0f5; | ||
} | ||
|
||
.button-section { | ||
padding: 12px; | ||
display: flex; | ||
justify-content: center; | ||
flex-direction: column; | ||
align-items: center; | ||
} | ||
|
||
.setting { | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
padding: 12px 16px; | ||
border-bottom: 1px solid #e0e0e0; | ||
cursor: pointer; | ||
} | ||
|
||
.setting:last-child { | ||
border-bottom: none; | ||
} | ||
|
||
.switch { | ||
position: relative; | ||
display: inline-block; | ||
width: 60px; | ||
height: 34px; | ||
-webkit-tap-highlight-color: transparent; | ||
-webkit-touch-callout: none; | ||
-webkit-user-select: none; | ||
-khtml-user-select: none; | ||
-moz-user-select: none; | ||
-ms-user-select: none; | ||
user-select: none; | ||
} | ||
|
||
.switch input { | ||
display: none; | ||
} | ||
|
||
.slider { | ||
position: absolute; | ||
cursor: pointer; | ||
top: 0; | ||
left: 0; | ||
right: 0; | ||
bottom: 0; | ||
background-color: #ccc; | ||
transition: background-color 0.4s; | ||
border-radius: 34px; | ||
} | ||
|
||
.slider:before { | ||
position: absolute; | ||
content: ""; | ||
height: 26px; | ||
width: 26px; | ||
left: 4px; | ||
bottom: 4px; | ||
background-color: white; | ||
transition: transform 0.4s; | ||
border-radius: 50%; | ||
} | ||
|
||
input:checked + .slider { | ||
background-color: #2196F3; | ||
} | ||
|
||
input:checked + .slider:before { | ||
transform: translateX(26px); | ||
} | ||
|
||
.button { | ||
padding: 12px 72px; | ||
margin: 4px 8px; | ||
transition: background-color 0.3s; | ||
box-sizing: border-box; | ||
border-radius: 12px; | ||
} | ||
|
||
.button:hover { | ||
opacity: 0.8; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div class="content-container"> | ||
<div class="title"> | ||
<h1>Javascript Bridge<br>Test Page</h1> | ||
</div> | ||
|
||
<div class="section"> | ||
<div class="section-title">Toggle</div> | ||
<div class="setting"> | ||
<span id="toggle-status">Toggle is off</span> | ||
<label class="switch"> | ||
<input type="checkbox" name="myCheckbox"> | ||
<span class="slider round"></span> | ||
</label> | ||
</div> | ||
</div> | ||
|
||
<div class="section"> | ||
<div class="section-title">Buttons</div> | ||
<div class="button-section"> | ||
<button class="button" id="close-button">Close</button> | ||
</div> | ||
</div> | ||
|
||
<!-- Added placeholder content to force scrolling --> | ||
<div class="section"> | ||
<div class="section-title">Placeholder Content</div> | ||
<div class="setting"> | ||
<span>Item 1</span> | ||
</div> | ||
<div class="setting"> | ||
<span>Item 2</span> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<script> | ||
document.getElementById("close-button").addEventListener("click", function() { | ||
window.close(); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
74 changes: 74 additions & 0 deletions
74
Sources/KlaviyoUI/KlaviyoWebView/Development Assets/JSTestWebViewModel.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// JSTestWebViewModel.swift | ||
// klaviyo-swift-sdk | ||
// | ||
// Created by Andrew Balmer on 11/18/24. | ||
// | ||
|
||
#if DEBUG | ||
import Combine | ||
import Foundation | ||
import WebKit | ||
|
||
class JSTestWebViewModel: KlaviyoWebViewModeling { | ||
let url: URL | ||
let loadScripts: [String: WKUserScript]? | ||
|
||
/// Publishes scripts for the `WKWebView` to execute. | ||
private var continuation: AsyncStream<(script: String, callback: ((Result<Any?, Error>) -> Void)?)>.Continuation? | ||
lazy var scriptStream: AsyncStream<(script: String, callback: ((Result<Any?, Error>) -> Void)?)> = AsyncStream { [weak self] continuation in | ||
self?.continuation = continuation | ||
} | ||
|
||
init(url: URL) { | ||
self.url = url | ||
loadScripts = JSTestWebViewModel.initializeLoadScripts() | ||
} | ||
|
||
private static func initializeLoadScripts() -> [String: WKUserScript] { | ||
var scripts: [String: WKUserScript] = [:] | ||
|
||
if let toggleHandlerScript = try? FileIO.getFileContents(path: "toggleHandler", type: "js") { | ||
let script = WKUserScript(source: toggleHandlerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: true) | ||
scripts["toggleMessageHandler"] = script | ||
} | ||
|
||
return scripts | ||
} | ||
|
||
// MARK: handle WKWebView events | ||
|
||
func handleNavigationEvent(_ event: WKNavigationEvent) { | ||
// TODO: handle navigation events | ||
} | ||
|
||
func handleScriptMessage(_ message: WKScriptMessage) { | ||
if message.name == "toggleMessageHandler" { | ||
guard let dict = message.body as? [String: AnyObject] else { | ||
return | ||
} | ||
|
||
guard let toggleEnabled = dict["toggleEnabled"] as? Bool else { | ||
return | ||
} | ||
|
||
print("toggle enabled: \(toggleEnabled)") | ||
|
||
let newStatus = toggleEnabled ? "Toggle is on" : "Toggle is off" | ||
|
||
let script = "document.getElementById('toggle-status').innerText = \"\(newStatus)\"" | ||
|
||
continuation?.yield((script, { result in | ||
switch result { | ||
case let .success(content): | ||
if let successMessage = content as? String { | ||
print("Successfully evaluated Javascript; message: \(successMessage)") | ||
} | ||
case let .failure(failure): | ||
print("Javascript evaluation failed; message: \(failure.localizedDescription)") | ||
} | ||
})) | ||
} | ||
} | ||
} | ||
#endif |
74 changes: 74 additions & 0 deletions
74
Sources/KlaviyoUI/KlaviyoWebView/Development Assets/PreviewGridViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// PreviewGridViewController.swift | ||
// klaviyo-swift-sdk | ||
// | ||
// Created by Andrew Balmer on 10/23/24. | ||
// | ||
|
||
#if DEBUG | ||
import Foundation | ||
import UIKit | ||
|
||
/// A sample grid view with randomly-colored tiles for internal Xcode preview purposes only. | ||
class PreviewGridViewController: UIViewController, UICollectionViewDataSource { | ||
var collectionView: UICollectionView! | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
|
||
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1.0)) | ||
let item = NSCollectionLayoutItem(layoutSize: itemSize) | ||
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.4)) | ||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) | ||
group.interItemSpacing = .flexible(12) | ||
let section = NSCollectionLayoutSection(group: group) | ||
section.interGroupSpacing = 12 | ||
section.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16) | ||
|
||
let layout = UICollectionViewCompositionalLayout(section: section) | ||
|
||
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) | ||
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell") | ||
collectionView.dataSource = self | ||
|
||
view.addSubview(collectionView) | ||
|
||
// Disable autoresizing mask translation for Auto Layout | ||
collectionView.translatesAutoresizingMaskIntoConstraints = false | ||
|
||
// Set up constraints using safeAreaLayoutGuide | ||
NSLayoutConstraint.activate([ | ||
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), | ||
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), | ||
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), | ||
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) | ||
]) | ||
} | ||
|
||
// MARK: UICollectionViewDataSource | ||
|
||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { | ||
12 | ||
} | ||
|
||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { | ||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) | ||
cell.backgroundColor = UIColor( | ||
red: .random(in: 0...1), | ||
green: .random(in: 0...1), | ||
blue: .random(in: 0...1), | ||
alpha: 1.0) | ||
cell.layer.cornerRadius = 12.0 | ||
return cell | ||
} | ||
} | ||
|
||
// MARK: - Previews | ||
|
||
#if swift(>=5.9) | ||
@available(iOS 17.0, *) | ||
#Preview { | ||
PreviewTabViewController() | ||
} | ||
#endif | ||
#endif |
36 changes: 36 additions & 0 deletions
36
Sources/KlaviyoUI/KlaviyoWebView/Development Assets/PreviewTabViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// | ||
// PreviewTabViewController.swift | ||
// klaviyo-swift-sdk | ||
// | ||
// Created by Andrew Balmer on 10/23/24. | ||
// | ||
|
||
#if DEBUG | ||
import Foundation | ||
import UIKit | ||
|
||
/// A sample tab view for internal Xcode preview purposes only. | ||
class PreviewTabViewController: UITabBarController { | ||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
|
||
let firstVC = PreviewGridViewController() | ||
let secondVC = UIViewController() | ||
let thirdVC = UIViewController() | ||
|
||
firstVC.title = "Browse" | ||
|
||
firstVC.tabBarItem = UITabBarItem(title: "Browse", image: UIImage(systemName: "house"), tag: 0) | ||
secondVC.tabBarItem = UITabBarItem(title: "Search", image: UIImage(systemName: "magnifyingglass"), tag: 1) | ||
thirdVC.tabBarItem = UITabBarItem(title: "Profile", image: UIImage(systemName: "person"), tag: 2) | ||
|
||
viewControllers = [ | ||
UINavigationController(rootViewController: firstVC), | ||
UINavigationController(rootViewController: secondVC), | ||
UINavigationController(rootViewController: thirdVC) | ||
] | ||
|
||
firstVC.navigationController?.navigationBar.prefersLargeTitles = true | ||
} | ||
} | ||
#endif |
8 changes: 8 additions & 0 deletions
8
Sources/KlaviyoUI/KlaviyoWebView/Development Assets/Scripts/toggleHandler.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
var _selector = document.querySelector('input[name=myCheckbox]'); | ||
_selector.addEventListener('change', function(event) { | ||
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.toggleMessageHandler) { | ||
window.webkit.messageHandlers.toggleMessageHandler.postMessage({ | ||
"toggleEnabled": _selector.checked | ||
}); | ||
} | ||
}); |
Oops, something went wrong.