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