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

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)
}
}