Releases: swifweb/web
Releases · swifweb/web
🪚 Improve `@media` rule syntax
@main
public class App: WebApp {
@AppBuilder public override var body: AppBuilder.Content {
/// ...
MainStyle()
}
}
class MainStyle: Stylesheet {
@Rules override var rules: Rules.Content {
MediaRule(.screen.maxWidth(800.px)) {
Rule(Body.pointer)
.backgroundColor(.red)
}
MediaRule(.screen.maxWidth(1200.px)) {
Rule(Body.pointer)
.backgroundColor(.green)
}
MediaRule(.screen.aspectRatio(4/3)) {
Rule(Body.pointer)
.backgroundColor(.purple)
}
MediaRule(!.screen.aspectRatio(4/3)) {
Rule(Body.pointer)
.backgroundColor(.black)
}
}
}
which represents
@media only screen and (max-width: 800px) {
background-color: red;
}
@media only screen and (max-width: 1200px) {
background-color: green;
}
@media only screen and (aspect-ratio: 4/3) {
background-color: purple;
}
@media not screen and (aspect-ratio: 4/3) {
background-color: black;
}
🪚 Implement simpler `@State` with `UnitValue`
Normal usage without @State
Div().height(100.px) // static value
Usage with @State
@State var height = 100.px // this way you even can change px to em on the fly
Div().height($height)
New option
@State var height: Double = 100 // this way you can change digit value only
Div().height($height.px)
🪚 Allow to put raw HTML string into `@DOM` block
@DOM override var body: DOM.Content {
"""
<button>Hello world</button>
"""
}
which represents
<div>
<button>Hello world</button>
</div>
🌎Localization
Static localization
Classic localization is automatic and depends on user system language
How to use
H1(String(
.en("Hello"),
.fr("Bonjour"),
.ru("Привет"),
.es("Hola"),
.zh_Hans("你好"),
.ja("こんにちは")))
Dynamic localization
If you want to change localized strings on the screen on-the-fly (without page reloading)
You could change current language by calling
Localization.current = .es
If you saved user's language somewhere in cookies or localstorage then you have to set it on app launch
Lifecycle.didFinishLaunching {
Localization.current = .es
}
How to use
H1(LString(
.en("Hello"),
.fr("Bonjour"),
.ru("Привет"),
.es("Hola"),
.zh_Hans("你好"),
.ja("こんにちは")))
Advanced example
H1(Localization.currentState.map { "Curent language: \($0.rawValue)" })
H2(LString(.en("English string"), .es("Hilo Español")))
Button("change lang").onClick {
Localization.current = Localization.current.rawValue.contains("en") ? .es : .en
}
🪚 Implement `Img().load(url:)` by @tierracero
The following method allows to load an image async while showing a default image.
Once the image has loaded in the background it will replace existing img.src
Img()
.src("/images/placeholder.jpg")
.loading(.lazy)
.load("http://google.com/images/cat.jpg")
So the code above will first show placeholder.jpg
image, then once cat.jpg
is ready to show it will replace placeholder.jpg
🚀 Implement StreamsAPI, FetchAPI, XMLHttpRequest, WebSocketAPI
Fetch
import FetchAPI
Fetch("https://jsonplaceholder.typicode.com/todos/1") {
switch $0 {
case .failure:
break
case .success(let response):
print("response.code: \(response.status)")
print("response.statusText: \(response.statusText)")
print("response.ok: \(response.ok)")
print("response.redirected: \(response.redirected)")
print("response.headers: \(response.headers.dictionary)")
struct Todo: Decodable {
let id, userId: Int
let title: String
let completed: Bool
}
response.json(as: Todo.self) {
switch $0 {
case .failure(let error):
break
case .success(let todo):
print("decoded todo: \(todo)")
}
}
}
}
XMLHttpRequest
import XMLHttpRequest
XMLHttpRequest()
.open(method: "GET", url: "https://jsonplaceholder.typicode.com/todos/1")
.onAbort {
print("XHR onAbort")
}.onLoad {
print("XHR onLoad")
}.onError {
print("XHR onError")
}.onTimeout {
print("XHR onTimeout")
}.onProgress{ progress in
print("XHR onProgress")
}.onLoadEnd {
print("XHR onLoadEnd")
}.onLoadStart {
print("XHR onLoadStart")
}.onReadyStateChange { readyState in
print("XHR onReadyStateChange")
}
.send()
WebSocket
import WebSocket
let webSocket = WebSocket("wss://echo.websocket.org").onOpen {
print("ws connected")
}.onClose { (closeEvent: CloseEvent) in
print("ws disconnected code: \(closeEvent.code) reason: \(closeEvent.reason)")
}.onError {
print("ws error")
}.onMessage { message in
print("ws message: \(message)")
switch message.data {
case .arrayBuffer(let arrayBuffer): break
case .blob(let blob): break
case .text(let text): break
case .unknown(let jsValue): break
}
}
Dispatch.asyncAfter(2) {
// send as simple string
webSocket.send("Hello from SwifWeb")
// send as Blob
webSocket.send(Blob("Hello from SwifWeb"))
}
🖥 Implement live preview for VSCode
look into vsce-livepreview repo