diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 33bd6fa..579eb51 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,4 +1,3 @@ -import cats.data.* import cats.effect.* import cats.effect.syntax.all.* import cats.syntax.all.* @@ -15,40 +14,6 @@ import snow.* import Utils.* import Components.* -object Store { - def apply(window: Window[IO]): Resource[IO, Store] = { - val key = "nak-input" - - for { - inputRef <- SignallingRef[IO].of("").toResource - - _ <- Resource.eval { - OptionT(window.localStorage.getItem(key)) - .foreachF(inputRef.set(_)) - } - - _ <- window.localStorage - .events(window) - .foreach { - case Storage.Event.Updated(`key`, _, value, _) => - inputRef.set(value) - case _ => IO.unit - } - .compile - .drain - .background - - _ <- inputRef.discrete - .foreach(input => IO.cede *> window.localStorage.setItem(key, input)) - .compile - .drain - .background - } yield new Store(inputRef) - } -} - -case class Store(input: SignallingRef[IO, String]) - object Main extends IOWebApp { def render: Resource[IO, HtmlDivElement[IO]] = Store(window).flatMap { store => @@ -120,23 +85,18 @@ object Main extends IOWebApp { def result(store: Store): Resource[IO, HtmlDivElement[IO]] = div( cls := "w-full flex my-5", - store.input.map { input => - if input.trim() == "" then div("") - else - Parser.parseInput(input) match { - case Left(msg) => div(msg) - case Right(event: Event) => - renderEvent(event) - case Right(pp: ProfilePointer) => renderProfilePointer(pp) - case Right(evp: EventPointer) => renderEventPointer(evp) - case Right(sk: PrivateKey) => - renderProfilePointer( - ProfilePointer(pubkey = sk.publicKey.xonly), - Some(sk) - ) - case Right(addr: AddressPointer) => renderAddressPointer(addr) - } - + store.result.map { + case Left(msg) => div(msg) + case Right(event: Event) => + renderEvent(event) + case Right(pp: ProfilePointer) => renderProfilePointer(pp) + case Right(evp: EventPointer) => renderEventPointer(evp) + case Right(sk: PrivateKey) => + renderProfilePointer( + ProfilePointer(pubkey = sk.publicKey.xonly), + Some(sk) + ) + case Right(addr: AddressPointer) => renderAddressPointer(addr) } ) } diff --git a/src/main/scala/Parser.scala b/src/main/scala/Parser.scala index ff067d0..cb30d19 100644 --- a/src/main/scala/Parser.scala +++ b/src/main/scala/Parser.scala @@ -3,13 +3,13 @@ import cats.syntax.all.* import scoin.* import snow.* -import Components.* +type Result = Either[ + String, + Event | PrivateKey | AddressPointer | EventPointer | ProfilePointer +] object Parser { - def parseInput(input: String): Either[ - String, - Event | PrivateKey | AddressPointer | EventPointer | ProfilePointer - ] = + def parseInput(input: String): Result = NIP19.decode(input) match { case Right(pp: ProfilePointer) => Right(pp) case Right(evp: EventPointer) => Right(evp) diff --git a/src/main/scala/Store.scala b/src/main/scala/Store.scala new file mode 100644 index 0000000..7b73e34 --- /dev/null +++ b/src/main/scala/Store.scala @@ -0,0 +1,45 @@ +import cats.data.* +import cats.effect.* +import cats.effect.syntax.all.* +import cats.syntax.all.* +import fs2.concurrent.* +import fs2.dom.{Event => _, *} + +case class Store( + input: SignallingRef[IO, String], + result: SignallingRef[IO, Result] +) + +object Store { + def apply(window: Window[IO]): Resource[IO, Store] = { + val key = "nak-input" + + for { + input <- SignallingRef[IO].of("").toResource + result <- SignallingRef[IO, Result](Left("")).toResource + + _ <- Resource.eval { + OptionT(window.localStorage.getItem(key)) + .foreachF(input.set(_)) + } + + _ <- window.localStorage + .events(window) + .foreach { + case Storage.Event.Updated(`key`, _, value, _) => + input.set(value) + case _ => IO.unit + } + .compile + .drain + .background + + _ <- input.discrete + .evalTap(input => IO.cede *> window.localStorage.setItem(key, input)) + .evalTap(input => result.set(Parser.parseInput(input))) + .compile + .drain + .background + } yield Store(input, result) + } +}