mirror of
https://github.com/fiatjaf/nak.git
synced 2024-11-22 16:19:07 -05:00
148 lines
3.9 KiB
Scala
148 lines
3.9 KiB
Scala
import cats.effect.*
|
|
import cats.effect.syntax.all.*
|
|
import cats.syntax.all.*
|
|
import fs2.concurrent.*
|
|
import fs2.dom.{Event => _, *}
|
|
import io.circe.parser.*
|
|
import io.circe.syntax.*
|
|
import calico.*
|
|
import calico.html.io.{*, given}
|
|
import calico.syntax.*
|
|
import scoin.*
|
|
import snow.*
|
|
|
|
import Utils.*
|
|
import Components.*
|
|
|
|
object Main extends IOWebApp {
|
|
def render: Resource[IO, HtmlDivElement[IO]] = Store(window).flatMap {
|
|
store =>
|
|
div(
|
|
cls := "flex w-full h-full flex-col items-center justify-center",
|
|
div(
|
|
cls := "w-4/5",
|
|
h1(
|
|
cls := "px-1 py-2 text-center text-xl",
|
|
img(
|
|
cls := "inline-block w-8 mr-2",
|
|
src := "/favicon.ico"
|
|
),
|
|
a(
|
|
href := "/",
|
|
"nostr army knife"
|
|
)
|
|
),
|
|
div(
|
|
cls := "flex my-3",
|
|
input(store),
|
|
actions(store)
|
|
),
|
|
result(store)
|
|
),
|
|
div(
|
|
cls := "flex justify-end mr-5 mt-10 text-xs w-4/5",
|
|
a(
|
|
href := "https://github.com/fiatjaf/nak",
|
|
"source code"
|
|
),
|
|
a(
|
|
cls := "ml-4",
|
|
href := "https://github.com/fiatjaf/nak",
|
|
"get the command-line tool"
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
def actions(store: Store): Resource[IO, HtmlDivElement[IO]] =
|
|
div(
|
|
cls := "flex flex-col space-y-1 my-3",
|
|
store.input.map {
|
|
case "" => div("")
|
|
case _ =>
|
|
button(
|
|
Styles.button,
|
|
"clear",
|
|
onClick --> (_.foreach(_ => store.input.set("")))
|
|
)
|
|
},
|
|
store.result.map {
|
|
case Right(_: Event) =>
|
|
button(
|
|
Styles.button,
|
|
"format",
|
|
onClick --> (_.foreach(_ =>
|
|
store.input.update(original =>
|
|
parse(original).toOption
|
|
.map(_.printWith(jsonPrinter))
|
|
.getOrElse(original)
|
|
)
|
|
))
|
|
)
|
|
case _ => div("")
|
|
},
|
|
button(
|
|
Styles.button,
|
|
"generate event",
|
|
onClick --> (_.foreach(_ =>
|
|
store.input.set(
|
|
Event(
|
|
kind = 1,
|
|
content = "hello world"
|
|
).sign(keyOne)
|
|
.asJson
|
|
.printWith(jsonPrinter)
|
|
)
|
|
))
|
|
),
|
|
button(
|
|
Styles.button,
|
|
"generate keypair",
|
|
onClick --> (_.foreach(_ =>
|
|
store.input.set(
|
|
NIP19.encode(PrivateKey(randomBytes32()))
|
|
)
|
|
))
|
|
)
|
|
)
|
|
|
|
def input(store: Store): Resource[IO, HtmlDivElement[IO]] =
|
|
div(
|
|
cls := "w-full grow",
|
|
div(
|
|
cls := "w-full flex justify-center",
|
|
textArea.withSelf { self =>
|
|
(
|
|
cls := "w-full max-h-96 p-3 rounded",
|
|
styleAttr := "min-height: 280px; font-family: monospace",
|
|
spellCheck := false,
|
|
placeholder := "paste something nostric (event JSON, nprofile, npub, nevent etc or hex key or id)",
|
|
onInput --> (_.foreach(_ =>
|
|
self.value.get.flatMap(store.input.set)
|
|
)),
|
|
value <-- store.input
|
|
)
|
|
}
|
|
)
|
|
)
|
|
|
|
def result(store: Store): Resource[IO, HtmlDivElement[IO]] =
|
|
div(
|
|
cls := "w-full flex my-5",
|
|
store.result.map {
|
|
case Left(msg) => div(msg)
|
|
case Right(bytes: ByteVector32) => render32Bytes(bytes)
|
|
case Right(event: Event) => renderEvent(store, event)
|
|
case Right(pp: ProfilePointer) => renderProfilePointer(store, pp)
|
|
case Right(evp: EventPointer) => renderEventPointer(store, evp)
|
|
case Right(sk: PrivateKey) =>
|
|
renderProfilePointer(
|
|
store,
|
|
ProfilePointer(pubkey = sk.publicKey.xonly),
|
|
Some(sk)
|
|
)
|
|
case Right(addr: AddressPointer) => renderAddressPointer(store, addr)
|
|
}
|
|
)
|
|
}
|