You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
9.2 KiB
291 lines
9.2 KiB
package outwatchapp
|
|
|
|
import outwatch._
|
|
import outwatch.dsl._
|
|
|
|
import cats.effect.ExitCode
|
|
import monix.bio._
|
|
import colibri.ext.monix._
|
|
import monix.reactive.Observable
|
|
import scala.concurrent.duration._
|
|
import cats.implicits._
|
|
import outwatch.router.AppRouter
|
|
import outwatch.router.dsl._
|
|
import sttp.client.impl.monix.FetchMonixBackend
|
|
import outwatch.reactive.handlers.monix._
|
|
import sttp.client._
|
|
import monix.{eval => me}
|
|
import nova.monadic_sfx.ui.components.todo.TodoListStore
|
|
import outwatchapp.implicits._
|
|
import monix.eval.Coeval
|
|
import nova.monadic_sfx.ui.components.todo.Todo
|
|
|
|
object OutwatchApp extends BIOApp {
|
|
val counter2 = Observable.interval(1.second)
|
|
val counter = div(
|
|
"Hmm",
|
|
button(
|
|
onClick
|
|
.useScan(0)(_ + 1)
|
|
.handled(source => VDomModifier("Counter: ", source))
|
|
)
|
|
)
|
|
|
|
implicit val backend = FetchMonixBackend()
|
|
|
|
val handlerTask = Handler.createF[Task, String]("empty")
|
|
|
|
def request(query: String) = basicRequest
|
|
.get(
|
|
uri"https://jsonplaceholder.typicode.com/todos/${query.toIntOption.getOrElse(0)}"
|
|
)
|
|
.send()
|
|
.flatMap {
|
|
_.body match {
|
|
case Right(value) =>
|
|
me.Task(println(value)) >>
|
|
me.Task(value)
|
|
case Left(error) =>
|
|
me.Task(println(error)) >>
|
|
me.Task(error)
|
|
|
|
}
|
|
}
|
|
val component = Task.deferAction(implicit s =>
|
|
for {
|
|
handler <- handlerTask
|
|
todoContent <- Handler.createF[Task, String]
|
|
todoStore <- TodoListStore()
|
|
res <- Task(
|
|
div(
|
|
// cls := "col-lg-8 bd-example",
|
|
div(cls := "alert alert-danger", "Some Error Occured!"),
|
|
div(
|
|
form(
|
|
h4(cls := "form-title", "User Finder"),
|
|
div(
|
|
cls := "form-group",
|
|
label(
|
|
color := "hsla(0,0%,100%,0.8)",
|
|
forId := "httpInput",
|
|
"Enter an id: "
|
|
),
|
|
input(
|
|
idAttr := "httpInput",
|
|
typ := "text",
|
|
cls := "form-control",
|
|
placeholder := "0",
|
|
onInput.value --> handler
|
|
),
|
|
label(
|
|
color := "hsla(0,0%,100%,0.8)",
|
|
"Enter content for todo"
|
|
),
|
|
small(cls := "form-text text-muted", "default is 0")
|
|
),
|
|
div(
|
|
cls := "form-group",
|
|
input(
|
|
cls := "form-control",
|
|
onInput.value --> todoContent
|
|
),
|
|
button(
|
|
cls := "btn",
|
|
cls := "btn-info form-control",
|
|
"Add Todo",
|
|
onClick.preventDefault(
|
|
todoContent.map(TodoListStore.Add)
|
|
) --> todoStore.sink
|
|
)
|
|
)
|
|
)
|
|
),
|
|
div(
|
|
p(
|
|
cls := "profile-description",
|
|
handler
|
|
.doOnNext(str => me.Task(println(str)))
|
|
.mapEval(request)
|
|
.map(div(_)),
|
|
div(
|
|
"Todos: ",
|
|
todoStore.doOnNextF { case (a, s) => Coeval(println(s)) }.map {
|
|
case (a, s) => div(renderTodos(s.todos))
|
|
}
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
} yield res
|
|
)
|
|
|
|
def renderTodos(todos: Seq[Todo]) = div(
|
|
ul(
|
|
todos.map(todo => li(div(s"id: ${todo.id} content: ${todo.content}")))
|
|
)
|
|
)
|
|
|
|
sealed trait Page
|
|
case object Home extends Page
|
|
case object SomePage extends Page
|
|
case class UserHome(id: Int) extends Page
|
|
case object NotFound extends Page
|
|
|
|
val router = AppRouter.create[Task, Page](NotFound) {
|
|
case Root => Home
|
|
case Root / "user" / IntVar(id) => UserHome(id)
|
|
case Root / "some-page" => SomePage
|
|
}
|
|
val counterComponent =
|
|
Task.deferAction(implicit s =>
|
|
Task(div(p(cls := "profile-description", "count: ", counter2)))
|
|
)
|
|
|
|
def resolver: PartialFunction[Page, VDomModifier] = {
|
|
case Home =>
|
|
div(
|
|
div(cls := "title", "Home"),
|
|
div(
|
|
cls := "card",
|
|
div(
|
|
cls := "card-body",
|
|
counterComponent,
|
|
p(
|
|
cls := "profile-description",
|
|
div(
|
|
"hm",
|
|
htmlTag("blockQuote")(
|
|
cls := "blockquote",
|
|
p(
|
|
cls := "mb-0",
|
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante."
|
|
),
|
|
footer(
|
|
cls := "blockquote-footer",
|
|
"Someone famous in ",
|
|
cite(title := "Source Title", "Source Title")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
case SomePage =>
|
|
div(div(cls := "title", "SomePage"), component, div(cls := "slider"))
|
|
case UserHome(id) => div(div(cls := "title", "UserHome"), s"User id: $id")
|
|
case NotFound =>
|
|
div(
|
|
div(cls := "title", "NotFound"),
|
|
p(cls := "profile-description", "notfound")
|
|
)
|
|
}
|
|
|
|
def run(args: List[String]): UIO[ExitCode] = {
|
|
// div(h1("Hello World"), counterComponent, Task(1))
|
|
import org.scalajs.dom.document
|
|
val el =
|
|
document.createElement("div")
|
|
el.setAttribute("id", "#app")
|
|
document.body.appendChild(el)
|
|
|
|
router.store
|
|
.flatMap(implicit store =>
|
|
OutWatch
|
|
.renderInto(
|
|
el,
|
|
div(
|
|
htmlTag("nav")(
|
|
cls := "navbar navbar-expand-lg bg-primary ",
|
|
attr("color-on-scroll") := "100",
|
|
div(
|
|
cls := "container",
|
|
div(
|
|
cls := "navbar-translate",
|
|
a(
|
|
cls := "navbar-brand",
|
|
href := "https://demos.creative-tim.com/blk-design-system/index.html",
|
|
rel := "tooltip",
|
|
title := "",
|
|
attr("data-placement") := "bottom",
|
|
target := "_blank",
|
|
div("OutwatchApp")
|
|
),
|
|
button(
|
|
cls := "navbar-toggler navbar-toggler toggled collapsed",
|
|
attr("data-toggle") := "collapse",
|
|
attr("data-target") := "#navigation",
|
|
attr("aria-controls") := "navigation-index",
|
|
attr("aria-expanded") := "false",
|
|
attr("aria-label") := "Toggle navigation",
|
|
div(cls := "navbar-toggler-bar bar1"),
|
|
div(cls := "navbar-toggler-bar bar2"),
|
|
div(cls := "navbar-toggler-bar bar3")
|
|
)
|
|
),
|
|
div(
|
|
cls := "navbar-collapse justify-content-end collapse",
|
|
idAttr := "navigation",
|
|
div(
|
|
cls := "navbar-collapse-header",
|
|
div(
|
|
cls := "row",
|
|
div(
|
|
cls := "col-6 collapse-brand",
|
|
a("BLK•")
|
|
),
|
|
div(
|
|
cls := "col-6 collapse-close text-right",
|
|
button(
|
|
`type` := "button",
|
|
cls := "navbar-toggler collapsed",
|
|
attr("data-toggle") := "collapse",
|
|
attr("data-target") := "#navigation",
|
|
attr("aria-controls") := "navigation-index",
|
|
attr("aria-expanded") := "false",
|
|
attr("aria-label") := "Toggle navigation",
|
|
i(cls := "tim-icons icon-simple-remove")
|
|
)
|
|
)
|
|
)
|
|
),
|
|
ul(
|
|
cls := "navbar-nav",
|
|
li(
|
|
cls := "nav-item active",
|
|
router.link("/")(
|
|
cls := "nav-link",
|
|
"Home",
|
|
div(cls := "sr-only", "(current)")
|
|
)
|
|
),
|
|
li(
|
|
cls := "nav-item",
|
|
router
|
|
.link("/some-page")(cls := "nav-link", "SomePage")
|
|
),
|
|
li(
|
|
cls := "nav-item",
|
|
router.link("/user/1")(cls := "nav-link", "User Home")
|
|
),
|
|
li(
|
|
cls := "nav-item",
|
|
router.link("/todomvc")(cls := "nav-link", "TodoMvc")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
),
|
|
div(
|
|
cls := "container",
|
|
router.render(resolver),
|
|
router.watch()
|
|
)
|
|
)
|
|
)
|
|
)
|
|
.onErrorHandle(ex => UIO(ex.printStackTrace()))
|
|
.as(ExitCode.Success)
|
|
}
|
|
}
|