আপনার সুইফট ইনস্টল করা দরকার, এটি পাওয়ার সবচেয়ে সহজ উপায়:
brew install swifweb/tap/webber
সর্বশেষ সংস্করণে আপডেট করতে পরে চালান brew upgrade webber
sudo apt-get install binaryen curl //get.wasmer.io -sSfL | sh apt-get install npm cd /opt sudo git clone //github.com/swifweb/webber cd webber sudo swift build -c release sudo ln -s /opt/webber/.build/release/Webber /usr/local/bin/webber
শেষ সংস্করণে আপডেট করতে পরে চালান cd /opt/webber sudo git pull sudo swift build -c release
প্রধান শাখায় সর্বদা স্থিতিশীল কোড থাকে তাই নির্দ্বিধায় এটি থেকে আপডেটগুলি টানুন
webber new
ইন্টারেক্টিভ মেনুতে pwa
বা spa
বেছে নিন এবং প্রকল্পের নাম লিখুন।
নতুন তৈরি প্রকল্পে ডিরেক্টরি পরিবর্তন করুন এবং webber serve
চালান।
এই কমান্ডটি আপনার প্রোজেক্টকে WebAssembly-এ কম্পাইল করবে, একটি বিশেষ .webber
ফোল্ডারের মধ্যে সমস্ত প্রয়োজনীয় ফাইল প্যাকেজ করবে এবং ডিফল্টরূপে পোর্ট 8888
ব্যবহার করে সমস্ত ইন্টারফেসে আপনার প্রোজেক্ট পরিবেশন করা শুরু করবে।
webber serve
জন্য অতিরিক্ত আর্গুমেন্ট
-t pwa
প্রগ্রেসিভ ওয়েব অ্যাপের জন্য
-একক ওয়েব অ্যাপের জন্য -t spa
পরিষেবা কর্মীর লক্ষ্যের নাম (সাধারণত PWA প্রকল্পে Service
নামে পরিচিত)
-s Service
অ্যাপ টার্গেটের নাম ( ডিফল্টরূপে App
)
-a App
-v
ওয়েবার সার্ভারের জন্য পোর্ট (ডিফল্ট হল 8888
)
-p 8080
বাস্তব SSL এর মত পরীক্ষা করতে -p 443
ব্যবহার করুন (অনুমোদিত স্ব-স্বাক্ষরিত SSL সেটিং সহ)
--browser safari
বা --browser chrome
--browser-self-signed
--browser-incognito
অ্যাপটি Sources/App/App.swift
এ শুরু হয়
import Web @main class App: WebApp { @AppBuilder override var app: Configuration { Lifecycle.didFinishLaunching { app in app.registerServiceWorker("service") } Routes { Page { IndexPage() } Page("login") { LoginPage() } Page("article/:id") { ArticlePage() } Page("**") { NotFoundPage() } } MainStyle() } }
এটি একটি iOS-এর মতো পদ্ধতিতে কাজ করে:
didFinishLaunching
যখন অ্যাপটি সবেমাত্র শুরু হয়েছে
willTerminate
যখন অ্যাপটি মারা যাচ্ছে
willResignActive
যখন উইন্ডোটি নিষ্ক্রিয় হতে চলেছে
didBecomeActive
যখন উইন্ডো সক্রিয় থাকে
didEnterBackground
যখন উইন্ডোটি পটভূমিতে যাচ্ছে
willEnterForeground
যখন উইন্ডোটি ফোরগ্রাউন্ডে যাচ্ছে
এখানে সবচেয়ে দরকারী পদ্ধতি হল didFinishLaunching
কারণ এটি অ্যাপটি কনফিগার করার একটি দুর্দান্ত জায়গা। আপনি এটি সত্যিই একটি iOS অ্যাপ্লিকেশন মত মনে হয় দেখুন! 😀
এখানে app
দরকারী সুবিধার পদ্ধতি রয়েছে:
registerServiceWorker(“serviceName“)
কল করুন PWA পরিষেবা কর্মীকে নিবন্ধন করার জন্য
আপেক্ষিক বা বাহ্যিক স্ক্রিপ্ট যোগ করতে addScript(“path/to/script.js“)
কল করুন
আপেক্ষিক বা বাহ্যিক শৈলী যোগ করতে addStylesheet(“path/to/style.css“)
কল করুন
addFont(“path/to/font.woff”, type:)
আপেক্ষিক বা বাহ্যিক ফন্ট যোগ করতে কল করুন, ঐচ্ছিকভাবে সেট টাইপ
addIcon(“path/to/icon“, type:color:)
আইকন যোগ করতে কল, ঐচ্ছিকভাবে টাইপ এবং রঙ সেট করুন
//website.com/hello/world - এখানে /hello/world হল পথ
Page("/") { IndexPage() } Page("") { IndexPage() } Page { IndexPage() }
আমার মনে হয় শেষটা সবচেয়ে সুন্দর 🙂
Page("login") { LoginPage() } Page("registration") { RegistrationPage() }
প্যারামিটার-সম্পর্কিত রুট
Page("article/:id") { ArticlePage() }
উপরের উদাহরণে :id হল রুটের একটি গতিশীল অংশ। আমরা ArticlePage ক্লাসে এই আইডেন্টিফায়ারটি পুনরুদ্ধার করতে পারি এর সাথে যুক্ত নিবন্ধটি প্রদর্শন করতে।
class ArticlePage: PageController { override func didLoad(with req: PageRequest) { if let articleId = req.parameters.get("id") { // Retrieve article here } } }
পথের পরবর্তী আকর্ষণীয় জিনিসটি হল ক্যোয়ারী , যা ব্যবহার করাও খুব সহজ। উদাহরণ স্বরূপ, আসুন /অনুসন্ধান রুট বিবেচনা করা যাক, যা অনুসন্ধানের text
এবং age
ক্যোয়ারী প্যারামিটারগুলি আশা করে।
//website.com/search**?text=Alex&age=19** - শেষ অংশটি হল প্রশ্ন
Page("search") { SearchPage() }
এবং এই মত SearchPage ক্লাসে কোয়েরি ডেটা পুনরুদ্ধার করুন
class SearchPage: PageController { struct Query: Decodable { let text: String? let age: Int? } override func didLoad(with req: PageRequest) { do { let query = try req.query.decode(Query.self) // use optional query.text and query.age // to query search results } catch { print("Can't decode query: \(error)") } } }
আপনি রুট ঘোষণা করতে *
ব্যবহার করতে পারেন যা এই মত নির্দিষ্ট পাথ অংশে কিছু গ্রহণ করে
Page("foo", "*", "bar") { SearchPage() }
উপরের রুটটি foo এবং বারের মধ্যে যেকোনো কিছু গ্রহণ করবে, যেমন /foo/aaa/bar, /foo/bbb/bar, ইত্যাদি। **
চিহ্নের সাহায্যে আপনি একটি বিশেষ ক্যাচ-অল রুট সেট করতে পারেন যা নির্দিষ্ট পথে অন্য রুটের সাথে মেলেনি এমন কিছু পরিচালনা করবে।
Page("**") { NotFoundPage() }
অথবা নির্দিষ্ট পথের জন্য যেমন ব্যবহারকারী পাওয়া যায় না Page("user", "**") { UserNotFoundPage() }
/user/1 - যদি /user/:id এর জন্য একটি রুট থাকে তবে এটি UserPage ফেরত দেবে। অন্যথায়, এটি পড়ে যাবে...
UserNotFoundPage
/user/1/hello - যদি /user/:id/hello এর জন্য রুট থাকে তবে এটি UserNotFoundPage- এ পড়বে
/something - যদি /something-এর জন্য কোন রুট না থাকে তবে এটি NotFoundPage- এ পড়বে
আমরা পরবর্তী রুটের জন্য পৃষ্ঠার সম্পূর্ণ বিষয়বস্তু প্রতিস্থাপন করতে চাই না, তবে শুধুমাত্র কিছু ব্লক। এখানেই ফ্র্যাগমেন্ট রাউটার কাজে আসে!
আসুন আমরা বিবেচনা করি যে /ব্যবহারকারী পৃষ্ঠাতে আমাদের ট্যাব রয়েছে। প্রতিটি ট্যাব একটি সাবরাউট, এবং আমরা ফ্র্যাগমেন্ট রাউটার ব্যবহার করে সাবরাউটে পরিবর্তনের প্রতিক্রিয়া জানাতে চাই।
অ্যাপ ক্লাসে শীর্ষ-স্তরের রুট ঘোষণা করুন
Page("user") { UserPage() }
এবং UserPage ক্লাসে FragmentRouter ঘোষণা করুন
class UserPage: PageController { @DOM override var body: DOM.Content { // NavBar is from Materialize library :) Navbar() .item("Profile") { self.changePath(to: "/user/profile") } .item("Friends") { self.changePath(to: "/user/friends") } FragmentRouter(self) .routes { Page("profile") { UserProfilePage() } Page("friends") { UserFriendsPage() } } } }
উপরের উদাহরণে, ফ্র্যাগমেন্টরাউটার /user/profile এবং /user/friends সাবরাউটগুলি পরিচালনা করে এবং এটি Navbar এর অধীনে রেন্ডার করে, তাই পৃষ্ঠাটি কখনই সম্পূর্ণ বিষয়বস্তু পুনরায় লোড করে না কিন্তু শুধুমাত্র নির্দিষ্ট অংশগুলিকে।
Btw FragmentRouter হল একটি Div এবং আপনি কল করে এটি কনফিগার করতে পারেন
FragmentRouter(self) .configure { div in // do anything you want with the div }
সুইফট ব্যবহার করে একটি CSS নিয়ম ঘোষণা করতে আমাদের কাছে রয়েছে রুল অবজেক্ট।
Rule(...selector...) .alignContent(.baseline) .color(.red) // or rgba/hex color .margin(v: 0, h: .auto)
অথবা @resultBuilder ব্যবহার করে SwiftUI-এর মতো উপায় Rule(...selector...) { AlignContent(.baseline) Color(.red) Margin(v: 0, h: .auto) }
উভয় পথই সমান, যাইহোক, আমি টাইপ করার ঠিক পরে স্বয়ংসম্পূর্ণতার কারণে প্রথমটিকে পছন্দ করি .
😀
Rule(...selector...) .custom("customKey", "customValue")
Pointer("a")
কিন্তু সঠিক দ্রুত উপায় হল এই মত প্রয়োজনীয় HTML ট্যাগে .pointer
কল করে এটি তৈরি করা
H1.pointer // h1 A.pointer // a Pointer.any // * Class("myClass").pointer // .myClass Id("myId").pointer // #myId
এটি বেসিক পয়েন্টার সম্পর্কে, তবে তাদেরও মডিফায়ার রয়েছে যেমন :hover
:first
:first-child
ইত্যাদি।
H1.pointer.first // h1:first H1.pointer.firstChild // h1:first-child H1.pointer.hover // h1:hover
আপনি যেকোন বিদ্যমান সংশোধক ঘোষণা করতে পারেন, তারা সব উপলব্ধ। H1.class(.myClass) // h1.myClass H1.id(.myId) // h1#myId H1.id(.myId).disabled // h1#myId:disabled Div.pointer.inside(P.pointer) // div p Div.pointer.parent(P.pointer) // div > p Div.pointer.immediatedlyAfter(P.pointer) // Div + p P.pointer.precededBy(Ul.pointer) // p ~ ul
নিয়মে নির্বাচক কীভাবে ব্যবহার করবেন
Rule(Pointer("a")) // or Rule(A.pointer)
নিয়মে কিভাবে একাধিক নির্বাচক ব্যবহার করবেন
Rule(A.pointer, H1.id(.myId), Div.pointer.parent(P.pointer))
এটি নিম্নলিখিত CSS কোড তৈরি করে a, h1#myId, div > p { }
import Web @main class App: WebApp { enum Theme { case light, dark } @State var theme: Theme = .light @AppBuilder override var app: Configuration { // ... Lifecycle, Routes ... LightStyle().disabled($theme.map { $0 != .happy }) DarkStyle().disabled($theme.map { $0 != .sad }) } }
LightStyle এবং DarkStyle আলাদা ফাইলে বা যেমন App.swift-এ ঘোষণা করা যেতে পারে
class LightStyle: Stylesheet { @Rules override var rules: Rules.Content { Rule(Body.pointer).backgroundColor(.white) Rule(H1.pointer).color(.black) } } class DarkStyle: Stylesheet { @Rules override var rules: Rules.Content { Rule(Body.pointer).backgroundColor(.black) Rule(H1.pointer).color(.white) } }
App.current.theme = .light // to switch to light theme // or App.current.theme = .dark // to switch to dark theme
এবং এটি সম্পর্কিত স্টাইলশীটগুলি সক্রিয় বা নিষ্ক্রিয় করবে! এটা শান্ত না? 😎
কিন্তু আপনি বলতে পারেন যে সিএসএসের পরিবর্তে সুইফটে শৈলী বর্ণনা করা কঠিন, তাহলে কি লাভ?
import Web @main class App: WebApp { @State var reactiveColor = Color.cyan @AppBuilder override var app: Configuration { // ... Lifecycle, Routes ... MainStyle() } } extension Class { static var somethingCool: Class { "somethingCool" } } class MainStyle: Stylesheet { @Rules override var rules: Rules.Content { // for all elements with `somethingCool` class Rule(Class.hello.pointer) .color(App.current.$reactiveColor) // for H1 and H2 elements with `somethingCool` class Rule(H1.class(.hello), H2.class(.hello)) .color(App.current.$reactiveColor) } }
App.current.reactiveColor = .yellow // or any color you want
এবং এটি স্টাইলশীটে এবং এটি ব্যবহার করে এমন সমস্ত উপাদানগুলিতে রঙ আপডেট করবে 😜
class MainStyle: Stylesheet { @Rules override var rules: Rules.Content { // for all elements with `somethingCool` class Rule(Class.hello.pointer) .color(App.current.$reactiveColor) // for H1 and H2 elements with `somethingCool` class Rule(H1.class(.hello), H2.class(.hello)) .color(App.current.$reactiveColor) """ /* Raw CSS goes here */ body { margin: 0; padding: 0; } """ } }
আপনি যতবার প্রয়োজন ততবার কাঁচা CSS স্ট্রিংগুলি মিশ্রিত করতে পারেনরাউটার প্রতিটি রুটে পেজ রেন্ডার করছে। পৃষ্ঠা হল PageController থেকে উত্তরাধিকারসূত্রে প্রাপ্ত যেকোন শ্রেণী।
পেজ কন্ট্রোলারের লাইফসাইকেল পদ্ধতি রয়েছে যেমন willLoad
didLoad
willUnload
didUnload
, UI মেথড buildUI
এবং body
, এবং HTML উপাদানের জন্য প্রপার্টি র্যাপার ভেরিয়েবল।
টেকনিক্যালি পেজকন্ট্রোলার মাত্র একটি ডিভ এবং আপনি buildUI
পদ্ধতিতে এর যে কোনো বৈশিষ্ট্য সেট করতে পারেন।
class IndexPage: PageController { // MARK: - Lifecycle override func willLoad(with req: PageRequest) { super.willLoad(with: req) } override func didLoad(with req: PageRequest) { super.didLoad(with: req) // set page title and metaDescription self.title = "My Index Page" self.metaDescription = "..." // also parse query and hash here } override func willUnload() { super.willUnload() } override func didUnload() { super.didUnload() } // MARK: - UI override func buildUI() { super.buildUI() // access any properties of the page's div here // eg self.backgroundcolor(.lightGrey) // optionally call body method here to add child HTML elements body { P("Hello world") } // or alternatively self.appendChild(P("Hello world")) } // the best place to declare any child HTML elements @DOM override var body: DOM.Content { H1("Hello world") P("Text under title") Button("Click me") { self.alert("Click!") print("button clicked") } } }
PageController { page in H1("Hello world") P("Text under title") Button("Click me") { page.alert("Click!") print("button clicked") } } .backgroundcolor(.lightGrey) .onWillLoad { page in } .onDidLoad { page in } .onWillUnload { page in } .onDidUnload { page in }
এটা সুন্দর এবং laconic না? 🥲
বোনাস সুবিধার পদ্ধতি
alert(message: String)
- সরাসরি জেএস alert
পদ্ধতি
changePath(to: String)
- ইউআরএল পাথ পরিবর্তন করা
সুইফওয়েব কোড | HTML কোড |
---|---|
| |
| |
| |
| |
| |
| |
সরল Div
Div()
আমরা এর মতো এর সমস্ত বৈশিষ্ট্য এবং শৈলী বৈশিষ্ট্যগুলি অ্যাক্সেস করতে পারি Div().class(.myDivs) // <div class="myDivs"> .id(.myDiv) // <div id="myDiv"> .backgroundColor(.green) // <div style="background-color: green;"> .onClick { // adds `onClick` listener directly to the DOM element print("Clicked on div") } .attribute("key", "value") // <div key="value"> .attribute("boolKey", true, .trueFalse) // <div boolKey="true"> .attribute("boolKey", true, .yesNo) // <div boolKey="yes"> .attribute("checked", true, .keyAsValue) // <div checked="checked"> .attribute("muted", true, .keyWithoutValue) // <div muted> .custom("border", "2px solid red") // <div style="border: 2px solid red;">
সাবক্লাস এইচটিএমএল উপাদান এটির জন্য পূর্বনির্ধারিত শৈলী নির্ধারণ করতে, অথবা অনেকগুলি পূর্বনির্ধারিত চাইল্ড উপাদান এবং বাইরে উপলব্ধ কিছু সুবিধাজনক পদ্ধতি সহ একটি যৌগিক উপাদান তৈরি করতে, বা didAddToDOM
এবং didRemoveFromDOM
এর মতো জীবনচক্র ইভেন্টগুলি অর্জন করতে।
চলুন একটি Divider
এলিমেন্ট তৈরি করি যা শুধুমাত্র একটি Div
কিন্তু পূর্বনির্ধারিত .divider
ক্লাস সহ
public class Divider: Div { // it is very important to override the name // because otherwise it will be <divider> in HTML open class override var name: String { "\(Div.self)".lowercased() } required public init() { super.init() } // this method executes immediately after any init method public override func postInit() { super.postInit() // here we are adding `divider` class self.class(.divider) } }
এলিমেন্টটি এখনই বা পরে PageController বা HTML উপাদানের DOM-এ যুক্ত করা যেতে পারে।
Div { H1("Title") P("Subtitle") Div { Ul { Li("One") Li("Two") } } }
অথবা পরে lazy var
ব্যবহার করে
lazy var myDiv1 = Div() lazy var myDiv2 = Div() Div { myDiv1 myDiv2 }
তাই আপনি আগে থেকে একটি HTML উপাদান ঘোষণা করতে পারেন এবং পরে যেকোনো সময় এটি DOM-এ যোগ করতে পারেন!
lazy var myDiv = Div() Div { myDiv } // somewhere later myDiv.remove()
Div().superview?.backgroundColor(.red)
আমাদের প্রায়শই শুধুমাত্র নির্দিষ্ট পরিস্থিতিতে উপাদানগুলি দেখাতে হয় তাই এর জন্য if/else
ব্যবহার করি
lazy var myDiv1 = Div() lazy var myDiv2 = Div() lazy var myDiv3 = Div() var myDiv4: Div? var showDiv2 = true Div { myDiv1 if showDiv2 { myDiv2 } else { myDiv3 } if let myDiv4 = myDiv4 { myDiv4 } else { P("Div 4 was nil") } }
কিন্তু এটি প্রতিক্রিয়াশীল নয়। আপনি showDiv2
false
সেট করার চেষ্টা করলে কিছুই হবে না।
lazy var myDiv1 = Div() lazy var myDiv2 = Div() lazy var myDiv3 = Div() @State var showDiv2 = true Div { myDiv1 myDiv2.hidden($showDiv2.map { !$0 }) // shows myDiv2 if showDiv2 == true myDiv3.hidden($showDiv2.map { $0 }) // shows myDiv3 if showDiv2 == false }
কেন আমরা $showDiv2.map {…}
ব্যবহার করব ?
নীচে @State
সম্পর্কে আরও পড়ুন ।
Div { """ <a href="//google.com">Go to Google</a> """ }
let names = ["Bob", "John", "Annie"] Div { ForEach(names) { name in Div(name) } // or ForEach(names) { index, name in Div("\(index). \(name)") } // or with range ForEach(1...20) { index in Div() } // and even like this 20.times { Div().class(.shootingStar) } }
@State var names = ["Bob", "John", "Annie"] Div { ForEach($names) { name in Div(name) } // or with index ForEach($names) { index, name in Div("\(index). \(name)") } } Button("Change 1").onClick { // this will append new Div with name automatically self.names.append("George") } Button("Change 2").onClick { // this will replace and update Divs with names automatically self.names = ["Bob", "Peppa", "George"] }
উপরের উদাহরণগুলির মতোই, তবে BuilderFunction
উপলব্ধ
Stylesheet { ForEach(1...20) { index in CSSRule(Div.pointer.nthChild("\(index)")) // set rule properties depending on index } 20.times { index in CSSRule(Div.pointer.nthChild("\(index)")) // set rule properties depending on index } }
আপনি ForEach
লুপগুলিতে BuilderFunction
ব্যবহার করতে পারেন শুধুমাত্র নিম্নলিখিত উদাহরণে একটি delay
মানের মত কিছু মান একবার গণনা করতে
ForEach(1...20) { index in BuilderFunction(9999.asRandomMax()) { delay in CSSRule(Pointer(".shooting_star").nthChild("\(index)")) .custom("top", "calc(50% - (\(400.asRandomMax() - 200)px))") .custom("left", "calc(50% - (\(300.asRandomMax() + 300)px))") .animationDelay(delay.ms) CSSRule(Pointer(".shooting_star").nthChild("\(index)").before) .animationDelay(delay.ms) CSSRule(Pointer(".shooting_star").nthChild("\(index)").after) .animationDelay(delay.ms) } }
BuilderFunction(calculate) { calculatedValue in // CSS rule or DOM element } func calculate() -> Int { return 1 + 1 }
বিল্ডার ফাংশন এইচটিএমএল উপাদানগুলির জন্যও উপলব্ধ :)
@State
আজকাল ঘোষণামূলক প্রোগ্রামিংয়ের জন্য সবচেয়ে আকাঙ্ক্ষিত জিনিস।
enum Countries { case usa, australia, mexico } @State var selectedCounty: Countries = .usa $selectedCounty.listen { print("country changed") } $selectedCounty.listen { newValue in print("country changed to \(newValue)") } $selectedCounty.listen { oldValue, newValue in print("country changed from \(oldValue) to \(newValue)") }
@State var text = "Hello world!" H1($text) // whenever text changes it updates inner-text in H1 InputText($text) // while user is typing text it updates $text which updates H1
সহজ সংখ্যা উদাহরণ @State var height = 20.px Div().height($height) // whenever height var changes it updates height of the Div
সহজ বুলিয়ান উদাহরণ @State var hidden = false Div().hidden($hidden) // whenever hidden changes it updates visibility of the Div
ম্যাপিং উদাহরণ @State var isItCold = true H1($isItCold.map { $0 ? "It is cold 🥶" : "It is not cold 😌" })
দুটি রাজ্যের ম্যাপিং @State var one = true @State var two = true Div().display($one.and($two).map { one, two in // returns .block if both one and two are true one && two ? .block : .none })
দুইটির বেশি রাজ্যের ম্যাপিং @State var one = true @State var two = true @State var three = 15 Div().display($one.and($two).map { one, two in // returns true if both one and two are true one && two }.and($three).map { oneTwo, three in // here oneTwo is a result of the previous mapping // returns .block if oneTwo is true and three is 15 oneTwo && three == 15 ? .block : .none })
সমস্ত HTML এবং CSS বৈশিষ্ট্য @State
মানগুলি পরিচালনা করতে পারে
extension Div { func makeItBeautiful() {} }
অথবা উপাদানের গোষ্ঠী যদি আপনি তাদের পিতামাতার class
জানেন।
কয়েকটি অভিভাবক ক্লাস আছে।
BaseActiveStringElement
- এমন উপাদানগুলির জন্য যা স্ট্রিং দিয়ে শুরু করা যেতে পারে, যেমন a
, h1
, ইত্যাদি।
BaseContentElement
- সমস্ত উপাদানের জন্য যা এর ভিতরে বিষয়বস্তু থাকতে পারে, যেমন div
, ul
, ইত্যাদি।
BaseElement
- সমস্ত উপাদানের জন্য
extension BaseElement { func doSomething() {} }
রঙের শ্রেণী রঙের জন্য দায়ী। এটিতে পূর্বনির্ধারিত HTML-রঙ রয়েছে, তবে আপনার নিজস্ব থাকতে পারে
extension Color { var myColor1: Color { .hex(0xf1f1f1) } // which is 0xF1F1F1 var myColor2: Color { .hsl(60, 60, 60) } // which is hsl(60, 60, 60) var myColor3: Color { .hsla(60, 60, 60, 0.8) } // which is hsla(60, 60, 60, 0.8) var myColor4: Color { .rgb(60, 60, 60) } // which is rgb(60, 60, 60) var myColor5: Color { .rgba(60, 60, 60, 0.8) } // which is rgba(60, 60, 60, 0.8) }
তারপর এটি H1(“Text“).color(.myColor1)
এর মত ব্যবহার করুন
extension Class { var my: Class { "my" } }
তারপর Div().class(.my)
এর মত ব্যবহার করুন
extension Id { var myId: Id { "my" } }
তারপর Div().id(.my)
এর মত ব্যবহার করুন
window
অবজেক্ট সম্পূর্ণরূপে মোড়ানো এবং App.current.window
ভেরিয়েবলের মাধ্যমে অ্যাক্সেসযোগ্য।
আপনি App.swift
এ Lifecycle
বা সরাসরি এইভাবে এটি শুনতে পারেন
App.current.window.$isInForeground.listen { isInForeground in // foreground flag changed }
অথবা যে কোন সময় যে কোন জায়গায় এটি পড়ুন if App.current.window.isInForeground { // do somethign }
অথবা এইচটিএমএল উপাদানের সাথে এটিতে প্রতিক্রিয়া দেখান Div().backgroundColor(App.current.window.$isInForeground.map { $0 ? .grey : .white })
এটি ফোরগ্রাউন্ড পতাকার মতই, কিন্তু App.current.window.isActive
এর মাধ্যমে অ্যাক্সেসযোগ্য
ফোরগ্রাউন্ড পতাকার মতই, কিন্তু App.current.window.isOnline
মাধ্যমে অ্যাক্সেসযোগ্য
ফোরগ্রাউন্ড পতাকার মতই, কিন্তু App.current.window.isDark
এর মাধ্যমে অ্যাক্সেসযোগ্য
App.current.window.innerSize
হল সাইজ অবজেক্টের ভিতরে width
এবং height
মান।
@State
ভেরিয়েবল হিসাবেও উপলব্ধ।
App.current.window.outerSize
হল সাইজ অবজেক্টের ভিতরে width
এবং height
মান।
@State
ভেরিয়েবল হিসাবেও উপলব্ধ।
স্ক্রিনের বৈশিষ্ট্যগুলি পরিদর্শনের জন্য বিশেষ বস্তু যেখানে বর্তমান উইন্ডোটি রেন্ডার করা হচ্ছে। App.current.window.screen
এর মাধ্যমে উপলব্ধ।
সবচেয়ে আকর্ষণীয় সম্পত্তি সাধারণত pixelRatio
হয়।
App.current.window.history
বা শুধু History.shared
এর মাধ্যমে উপলব্ধ।
এটি @State
ভেরিয়েবল হিসাবে অ্যাক্সেসযোগ্য, তাই প্রয়োজনে আপনি এর পরিবর্তনগুলি শুনতে পারেন।
App.current.window.$history.listen { history in // read history properties }
এটি সহজ পরিবর্তনশীল হিসাবে অ্যাক্সেসযোগ্য History.shared.length // size of the history stack History.shared.back() // to go back in history stack History.shared.forward() // to go forward in history stack History.shared.go(offset:) // going to specific index in history stack
আরও বিশদ এ উপলব্ধ। App.current.window.location
বা শুধু Location.shared
মাধ্যমে উপলব্ধ।
এটি @State
ভেরিয়েবল হিসাবে অ্যাক্সেসযোগ্য, তাই প্রয়োজনে আপনি এর পরিবর্তনগুলি শুনতে পারেন।
App.current.window.$location.listen { location in // read location properties }
Location.shared.href // also $href Location.shared.host // also $host Location.shared.port // also $port Location.shared.pathname // also $pathname Location.shared.search // also $search Location.shared.hash // also $hash
আরও বিশদ এ উপলব্ধ। App.current.window.navigator
বা শুধু Navigator.shared
এর মাধ্যমে উপলব্ধ
সবচেয়ে আকর্ষণীয় বৈশিষ্ট্য সাধারণত userAgent
platform
language
cookieEnabled
।
App.current.window.localStorage
বা শুধু LocalStorage.shared
হিসাবে উপলব্ধ।
// You can save any value that can be represented in JavaScript LocalStorage.shared.set("key", "value") // saves String LocalStorage.shared.set("key", 123) // saves Int LocalStorage.shared.set("key", 0.8) // saves Double LocalStorage.shared.set("key", ["key":"value"]) // saves Dictionary LocalStorage.shared.set("key", ["v1", "v2"]) // saves Array // Getting values back LocalStorage.shared.string(forKey: "key") // returns String? LocalStorage.shared.integer(forKey: "key") // returns Int? LocalStorage.shared.string(forKey: "key") // returns String? LocalStorage.shared.value(forKey: "key") // returns JSValue? // Removing item LocalStorage.shared.removeItem(forKey: "key") // Removing all items LocalStorage.shared.clear()
ট্র্যাকিং পরিবর্তন LocalStorage.onChange { key, oldValue, newValue in print("LocalStorage: key \(key) has been updated") }
সমস্ত আইটেম অপসারণ ট্র্যাকিং LocalStorage.onClear { print("LocalStorage: all items has been removed") }
App.current.window.sessionStorage
বা শুধু SessionStorage.shared
হিসাবে উপলব্ধ।
API উপরে বর্ণিত লোকালস্টোরেজের মতোই।
App.current.window.document
এর মাধ্যমে উপলব্ধ।
App.current.window.document.title // also $title App.current.window.document.metaDescription // also $metaDescription App.current.window.document.head // <head> element App.current.window.document.body // <body> element App.current.window.documentquerySelector("#my") // returns BaseElement? App.current.window.document.querySelectorAll(".my") // returns [BaseElement]
H1(String( .en("Hello"), .fr("Bonjour"), .ru("Привет"), .es("Hola"), .zh_Hans("你好"), .ja("こんにちは")))
Localization.current = .es
আপনি যদি ব্যবহারকারীর ভাষাটি কুকিজ বা স্থানীয় স্টোরেজে কোথাও সংরক্ষণ করেন তবে আপনাকে এটি অ্যাপ লঞ্চে সেট করতে হবে Lifecycle.didFinishLaunching { Localization.current = .es }
H1(LString( .en("Hello"), .fr("Bonjour"), .ru("Привет"), .es("Hola"), .zh_Hans("你好"), .ja("こんにちは")))
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 }
import FetchAPI Fetch("//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)") } } } }
import XMLHttpRequest XMLHttpRequest() .open(method: "GET", url: "//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()
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")) }
সহজ print(“Hello world“)
জাভাস্ক্রিপ্টে console.log('Hello world')
এর সমতুল্য
কনসোল পদ্ধতিগুলিও ভালবাসা দিয়ে মোড়ানো হয় ❤️
Console.dir(...) Console.error(...) Console.warning(...) Console.clear()
class IndexPage: PageController {} class Welcome_Preview: WebPreview { @Preview override class var content: Preview.Content { Language.en Title("Initial page") Size(640, 480) // add here as many elements as needed IndexPage() } }
VSCode এর ভিতরে এক্সটেনশনে যান এবং ওয়েবার অনুসন্ধান করুন।
এটি ইনস্টল হয়ে গেলে Cmd+Shift+P
(বা লিনাক্স/উইন্ডোজে Ctrl+Shift+P
) টিপুন।
Webber Live Preview
খুঁজুন এবং চালু করুন।
ডানদিকে, আপনি লাইভ প্রিভিউ উইন্ডো দেখতে পাবেন এবং যখনই আপনি ওয়েবপ্রিভিউ ক্লাস ধারণ করা ফাইলটি সংরক্ষণ করবেন তখন এটি রিফ্রেশ হবে।
এটি JavaScriptKit এর মাধ্যমে উপলব্ধ যা SwifWeb এর ভিত্তি।
পড়ুন আপনি কিভাবে আছেন। আপনি প্রকল্পের ভিতরে css
, js
, png
, jpg
, এবং অন্য কোন স্ট্যাটিক সম্পদ যোগ করতে পারেন।
কিন্তু ডিবাগের সময় বা চূড়ান্ত রিলিজ ফাইলে এগুলি উপলব্ধ করার জন্য আপনাকে প্যাকেজ.swift- এ এইভাবে ঘোষণা করতে হবে
.executableTarget(name: "App", dependencies: [ .product(name: "Web", package: "web") ], resources: [ .copy("css/*.css"), .copy("css"), .copy("images/*.jpg"), .copy("images/*.png"), .copy("images/*.svg"), .copy("images"), .copy("fonts/*.woff2"), .copy("fonts") ]),
পরে আপনি সেগুলি অ্যাক্সেস করতে সক্ষম হবেন যেমন Img().src(“/images/logo.png“)
নিম্নলিখিত উপায়ে ওয়েবার চালু করুন
webber serve
webber serve -t pwa -s Service
PWA মোডে চালু করতে
ডিবাগ করার উদ্দেশ্যে কনসোলে আরও তথ্য দেখানোর জন্য -v
বা --verbose
ডিফল্ট 8888 এর পরিবর্তে 443 পোর্টে ওয়েবার সার্ভার শুরু করতে -p 443
বা --port 443
--browser chrome/safari
স্বয়ংক্রিয়ভাবে পছন্দসই ব্রাউজার খুলতে, ডিফল্টরূপে এটি কোনো খোলে না
স্থানীয়ভাবে পরিষেবা কর্মীদের ডিবাগ করার জন্য --browser-self-signed
প্রয়োজন, অন্যথায় তারা কাজ করে না
--browser-incognito
ছদ্মবেশী মোডে ব্রাউজারের অতিরিক্ত উদাহরণ খুলতে, শুধুমাত্র ক্রোমের সাথে কাজ করে
webber serve --browser chrome
webber serve -t pwa -s Service -p 443 --browser chrome --browser-self-signed --browser-incognito
এর জন্য প্রজেক্টের ভিতরে .webber/entrypoint/dev
ফোল্ডার খুলুন এবং index.html
ফাইলটি সম্পাদনা করুন।
এটিতে খুব দরকারী শ্রোতাদের সাথে প্রাথমিক HTML কোড রয়েছে: WASMLoadingStarted
WASMLoadingStartedWithoutProgress
WASMLoadingProgress
WASMLoadingError
।
আপনি যখন নতুন বাস্তবায়ন শেষ করবেন তখন সেটিকে .webber/entrypoint/release
ফোল্ডারে সংরক্ষণ করতে ভুলবেন না
PWA-এর জন্য শুধু webber release
বা webber release -t pwa -s Service
চালান।
তারপর .webber/release
ফোল্ডার থেকে কম্পাইল করা ফাইলগুলিকে ধরুন এবং আপনার সার্ভারে আপলোড করুন৷
হোস্টিং ওয়াসম ফাইলের জন্য সঠিক কন্টেন্ট-টাইপ প্রদান করা উচিত!
হ্যাঁ, সঠিক শিরোনাম থাকা খুবই গুরুত্বপূর্ণ বিষয়বস্তু-প্রকার: wasm ফাইলের জন্য Content-Type: application/wasm
, অন্যথায় দুর্ভাগ্যবশত ব্রাউজার আপনার WebAssembly অ্যাপ্লিকেশন লোড করতে সক্ষম হবে না।
উদাহরণস্বরূপ GithubPages wasm ফাইলগুলির জন্য সঠিক সামগ্রী-প্রকার প্রদান করে না তাই দুর্ভাগ্যবশত এটিতে WebAssembly সাইটগুলি হোস্ট করা অসম্ভব৷
আপনি যদি nginx-এর সাথে আপনার নিজের সার্ভার ব্যবহার করেন, তাহলে /etc/nginx/mime.types
খুলুন এবং এতে application/wasm wasm;
রেকর্ড যদি হ্যাঁ তাহলে আপনি যেতে ভাল!
অনুগ্রহ করে যেকোনো একটিতে অবদান রাখতে এবং তাদের সবাইকে ⭐️তারকা দেওয়ার জন্য নির্দ্বিধায়!